I recall some discussion of there being an mpl::string template.....
Can't see it in the mpl library. Is it elsewhere?
Regards, Andy
_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users
I wrote one once and intended to write docs and tests and integrate it
into MPL but never got around to it. You can find it here:
http://archives.free.net.ph/message/20080324.060757.9880ea2b.el.html
--
Eric Niebler
BoostPro Computing
http://www.boostpro.com
Andy
Jesse Perla wrote:
> One rough idea I had was that since I will always have boost::function
> declarations as the default type, I could try to see if the type F is
> compatible with the boost::function type? Could this be done in a simple
> metafunction similar to the following:
>
> template<class BoostF, class F>
> struct CheckFunctionCompatible
> {
> static void Check()
> {
> F f;
> BoostF fboost = f; //If this fails, then I am basically failing
> }
> };
>
> But then if I instantiate, won't it also try to instantiate the constructor?
>
You could do it like this, but I doubt the error messages
from deep inside boost::function will be very helpful.
template<class BoostF, class F>
class CheckFunctionCompatible {
public:
BOOST_CONCEPT_USAGE(CheckFunctionCompatible) {
BoostF test(f);
}
private:
F f;
};
In Christ,
Steven Watanabe
You could do it like this, but I doubt the error messages
from deep inside boost::function will be very helpful.
template<class BoostF, class F>class CheckFunctionCompatible {
public:
BOOST_CONCEPT_USAGE(CheckFunctionCompatible) {
BoostF test(f);
}
private:
F f;
};
In Christ,
Steven Watanabe
I polished this up, wrote some docs and tests and submitted a patch.
It's up to Aleskey now.
https://svn.boost.org/trac/boost/ticket/2905
--
Eric Niebler
BoostPro Computing
http://www.boostpro.com
It has been added to trunk as of revision 52208:
https://svn.boost.org/trac/boost/changeset/52208
No doubt the regression tests will reveal portability problems. Once
they have been worked out, we can move this to release.
Why is this better than a metafunction c_str< Sequence >?
typedef mpl::vector_c<char, 'h', 'e', 'l', 'l', 'o'> str;
template < char const* sz >
struct x
{};
x< c_str<str>::value > test;
Is there some reason that's not possible or is prone to problems avoided
by mpl::string?
That is certainly a valid design. It's somewhat subjective, but IMO
multi-character literals give a nicer compile-time string interface.
Consider:
// With mpl::vector_c
mpl::vector_c<char, 'h','e','l','l','o',' ','w','o','r','l','d'>
// With mpl::string
mpl::string<'hell','o wo','rld'>
Neither will win a beauty contest, but my preference is strongly for the
latter.
--
Eric Niebler
BoostPro Computing
http://www.boostpro.com
Sent from my Verizon Wireless BlackBerry
Hi Eric,
I've been lurking on this thread for a while, and I'm intrigued by
"multi-character literals". Beside being new to me, a Google search
yields little information on them, beside the fact that "The value of
a narrow or wide character literal containing more than one character
or escape sequence is implementation-defined." Isn't this a problem
for mpl::string? Thanks, --DD
[2] http://bytes.com/groups/c/739845-multi-character-constant
"Implementation-defined" means that each compiler vendor is required to
document how multi-character literals are assigned integral values. A
library like MPL can use this information to provide a specialized
implementation for each compiler, presenting the user with a uniform
interface. And as it turns out, there is very little variation among
compiler vendors around the handling of multi-character literals. So
far, just one implementation has sufficed.
--
Eric Niebler
BoostPro Computing
http://www.boostpro.com
After reviewing the code it seems that all my concerns are taken care
of. It looks like it indeed iterates each individual character, not the
multicharacter literals. It also looks like iterating <'hel', 'lo w',
'orld', '!'> would be the same as iterating 'hell','o wo','rld!'>. So
pretty damn cool and some interesting techniques.
That said, I would still contemplate pulling the c_str out of the string
container proper. I would say that the mpl::string is not similar to
the std::string in that it actually has to be transformed (requiring
complete reconstruction) into a c_str; there's nothing about the
mpl::string that renders c_str easier or particular to this container
besides our prebias that it should be. That alone would indicate
separation to me but additionally if the c_str was a metafunction
separate from the string container, it could be used on any ForwardSequence.
Something to consider anyway. Thanks for adding this.
After reviewing the code it seems that all my concerns are taken care of. It looks like it indeed iterates each individual character, not the multicharacter literals. It also looks like iterating <'hel', 'lo w', 'orld', '!'> would be the same as iterating 'hell','o wo','rld!'>. So pretty damn cool and some interesting techniques.
That's correct.
>> So pretty damn cool and some interesting techniques.
>
> I agree with Noah.
Thanks.
> One more question, can you point to the compiler docs which you used
> as reference? I am just interested to read this it for my own.
You mean, how did I discover the nature of the implementation-defined
behavior for each compiler? It wasn't by reading any docs. I just played
around with various compilers until I found what worked. I found some
compiler bugs in the process, too. See:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=334208
--
Eric Niebler
BoostPro Computing
http://www.boostpro.com
That's not a bad suggestions, and I was on the fence myself about making
c_str a class static of mpl::string. My reason for doing so was that
getting a C-style string at compile time is really the only reason to
use mpl::string, and so accessing it shouldn't incur an extra template
instantiation.
A separate c_str metafunction might be useful, but to be a proper
metafunction, it would need to return a type, not a character array. But
as with Integral Constants, we could make:
mpl::c_str<FwdSeq>::type::value
synonymous with:
mpl::c_str<FwdSeq>::value
And mpl::c_str<FwdSeq>::type is probably just a typedef for
mpl::c_str<FwdSeq>.
Anyway, I've invested enough time in this already and am happy with the
result. If you'd like to see mpl::c_str<>, would you care to submit a
patch? Or at least open a feature-request Trac ticket?
--
Eric Niebler
BoostPro Computing
http://www.boostpro.com
You mean, how did I discover the nature of the implementation-defined behavior for each compiler? It wasn't by reading any docs. I just played around with various compilers until I found what worked. I found some compiler bugs in the process, too. See:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=334208
Well it wouldn't exactly be 'extra' would it? The mpl::string itself
would then never be instantiated since it contains nothing but typedefs
and such. You might need to make "size" an enum value...but it should
be at least possible to make string uninstantiated.
>
> A separate c_str metafunction might be useful, but to be a proper
> metafunction, it would need to return a type, not a character array. But
> as with Integral Constants, we could make:
>
> mpl::c_str<FwdSeq>::type::value
>
> synonymous with:
>
> mpl::c_str<FwdSeq>::value
>
> And mpl::c_str<FwdSeq>::type is probably just a typedef for
> mpl::c_str<FwdSeq>.
Right, it would be a value metafunction.
>
> Anyway, I've invested enough time in this already and am happy with the
> result. If you'd like to see mpl::c_str<>, would you care to submit a
> patch? Or at least open a feature-request Trac ticket?
>
I could see about doing it at home but I'm notorious for not doing so.
Interesting problem though, I might get to it.
Strings don't map to integers. Multicharacter literals do. And yes, that
means in general that you can only reliably count on being able to
encode a 4 char sequence in a multicharacter literal.
> I just looked over your tests and did not get immediately that these
> all use char test sequences.
I don't follow you.
> I used a slightly different approach in my previous use case.
>
> template<char const* Str> string {...};
>
> extern const char some_string[] ={"abcd efg..."};
>
> typedef string<some_string> my_string_type;
Sure, but that gets hard to use, and you can't use this to compute new
strings at compile time.
> Would be cool to find a solution of really passing strings like:
>
> typedef string<"abcd efg.."> some_other_type;
And if wishes were fishes we'd all cast nets. ;-)
I doubt any interesting metaprogram that uses mpl::string could avoid
instantiating mpl::string. What I don't know is whether the templates
needed to initialize mpl::string::c_str[] are instantiated even if
c_str[] is never referenced. If so, those instantiations are wasted.
That would be an argument in favor of moving c_str outside mpl::string.
There's another consideration that I've been glossing over. mpl::string
isn't *really* random access. Since mpl::string<'a','b','c'> designates
the same character sequence as mpl::string<'abc'>, it takes O(N)
template instantiations to find the N-th element in the sequence, at
least in the current implementation. I'd like to fix that, but I don't
know how (yet). It'd also be nice to be able to initialize the c_str[]
array without instantiating a pile of templates.
>> Anyway, I've invested enough time in this already and am happy with
>> the result. If you'd like to see mpl::c_str<>, would you care to
>> submit a patch? Or at least open a feature-request Trac ticket?
>
> I could see about doing it at home but I'm notorious for not doing so.
> Interesting problem though, I might get to it.
Yep, interesting. There are no small projects, it seems. <sigh>
--
Eric Niebler
BoostPro Computing
http://www.boostpro.com
Ovanes Markarian wrote:Strings don't map to integers. Multicharacter literals do. And yes, that
Eric Niebler wrote:
You mean, how did I discover the nature of the implementation-defined behavior for each compiler? It wasn't by reading any docs. I just played around with various compilers until
I found what worked. I found some compiler bugs in the process,
too. See:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=334208
Interesting. Ok, but if a string maps to an integer it means that I
can only pass 4 characters at once on a 32bit platform???
means in general that you can only reliably count on being able to
encode a 4 char sequence in a multicharacter literal.
I don't follow you.
I just looked over your tests and did not get immediately that these
all use char test sequences.
Sure, but that gets hard to use, and you can't use this to compute new strings at compile time.
I used a slightly different approach in my previous use case.
template<char const* Str> string {...};
extern const char some_string[] ={"abcd efg..."};
typedef string<some_string> my_string_type;
And if wishes were fishes we'd all cast nets. ;-)
Would be cool to find a solution of really passing strings like:
typedef string<"abcd efg.."> some_other_type;
Visual Studio 2005 hates it. Perhaps I'm not going about it the right
way? I simply downloaded string.hpp, char.hpp, and char_fwd.hpp and
altered the include paths so that they'd work in an individual project.
Then I wrote the following test code:
#include <iostream>
#include "string.hpp"
template < char const* str >
struct test
{
static void print() { std::cout << str << std::endl; }
};
int main()
{
typedef boost::mpl::string<'hell', 'o wo', 'rld!'> str;
std::cout << str::template at<0>::value << std::endl;
std::cin.get();
}
1>e:\dev_workspace\experimental\scratch\scratch\main.cpp(15) : error
C2976: 'boost::mpl::string<C0,C1,C2>::at' : too few template arguments
1> with
1> [
1> C0=1751477356,
1> C1=1864398703,
1> C2=1919706145
1> ]
This of course causes problems in c_str.
This code fails for the same reason:
#include <iostream>
#include <boost/type_traits.hpp>
template < typename T >
struct test_inner
{
template < typename X, bool B = boost::is_same<T,X>::value >
struct inner
{
static bool const value = B;
};
};
int main()
{
std::cout << test_inner<int>::template inner<int>::value << std::endl;
std::cin.get();
}
So, looks like VS can't handle default template arguments in these inner
templates. I changed the implementation of at<>:
template < typename String, long Pos, bool B = (Pos <
BOOST_MPL_MULTICHAR_LENGTH(String::front_)) >
struct string_at :
boost::mpl::char_<BOOST_MPL_MULTICHAR_AT(String::front_,Pos)>
{
};
template < typename String, long Pos >
struct string_at<String, Pos, false>
: string_at< typename String::rest_, Pos -
BOOST_MPL_MULTICHAR_LENGTH(String::front_)>
{
};
template<>
struct at_impl<string_tag>
{
template<typename Sequence, typename N>
struct apply
: string_at<Sequence, N::value>
{};
};
And implemented c_str[] in terms of string_at<>:
template<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS, unsigned
int C)>
char const string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS,
C)>::c_str[] =
{
#define M0(z, n, data)
string_at<string<BOOST_PP_ENUM_PARAMS(BOOST_MPL_STRING_MAX_PARAMS,C)>,
n>::value
BOOST_PP_ENUM(BOOST_MPL_STRING_MAX_LENGTH, M0, ~)
#undef M0
, '\0' // to ensure the string is null-terminated
};
This code compiles with changes in VS 2005:
#include <iostream>
#include <boost/mpl/at.hpp>
#include <boost/mpl/int.hpp>
#include "string.hpp"
int main()
{
typedef boost::mpl::string<'hell', 'o wo', 'rld!'> str;
std::cout << boost::mpl::at<str, boost::mpl::int_<0> >::value <<
std::endl;
std::cout << str::c_str << std::endl;
std::cin.get();
<snip>
Is that msvc-7.1? If so, I have already fixed the problem in changeset
52241. You can see that the string tests are passing for msvc-7.1, -8.0
and -9.0 by looking at the regression results.
Thanks,
--
Eric Niebler
BoostPro Computing
http://www.boostpro.com
No, it's msvc-8.0
Regression results aside, this doesn't compile:
#include <iostream>
#include <boost/mpl/at.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/string.hpp>
int main()
{
typedef boost::mpl::string<'hell', 'o wo', 'rld!'> str;
std::cout << boost::mpl::at<str, boost::mpl::int_<0> >::value <<
std::endl;
std::cout << str::c_str << std::endl;
std::cin.get();
}
Again, I simply copied char.hpp, char_fwd.hpp, and string.hpp into boost
1.37
It could be that it's because I'm not grabbing the entire boost tree
from svn but since I can replicate the problem with a basic program
that's using the same techniques you are, I really doubt that.
Looking deeper, you need to change:
#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
to:
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1400)
Alternatively, you could just keep telling me it's working and I'll go
away. I'm not loaded with a lot of spare time either.
Totally my bad. You're right. Looks like we don't have testers for
msvc-8.0, and I overlooked that. It should be fixed now. Thanks for the
report, and my apologies.
--
Eric Niebler
BoostPro Computing
http://www.boostpro.com
Now this is really bothering me. The right thing to do is replace the
current implementation with one in which mpl::string is a front- and
back-extensible bidirectional sequence, and give up with the random
access pretense. :-(
I've made this change. mpl::string is no longer random access (it never
really was). Also, I've changed c_str to be a separate metafunction that
works with any forward sequence.
Thanks particularly to Noah Roberts for the good feedback.
Nice work, guys!
--
Aleksey Gurtovoy
MetaCommunications Engineering
Now someone just needs to make format<> :P
Although a tongue-in-cheek remark, the notion of a compile-time
formatting library somehow appeals to me, if for nothing else for its
sheer absurdity ;)
Due to the limits of preprocessor stringization when dealing with
metaprogramming integers, I suspect it might have its use cases
wherever runtime conversion overhead is best avoided. With mpl::string
it's trivial to create integer-to-string conversion metafunctions, and
it should also not be overly complicated to glue these together into
something bigger if so should desired. I whipped up a quick (and not
very pretty) compile-time _itoa equivalent as a small proof of concept
just for fun (only tested on visual c++ 2008)
#include <iostream>
#include <boost/mpl/string.hpp>
#include <boost/mpl/vector_c.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/push_back.hpp>
namespace mpl = boost::mpl;
struct itoa_ct
{
// radix for _itoa() goes up to 36, but only bother with 16 here
typedef mpl::vector_c<char
,'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
> radix_t;
template <int Radix, unsigned int Quotient>
struct radix_convert
{
typedef typename mpl::push_back<
typename radix_convert<Radix, Quotient / Radix>::type
, mpl::char_<mpl::at_c<radix_t, Quotient % Radix>::type::value>
>::type type;
};
template <int Radix>
struct radix_convert<Radix, 0>
{
typedef mpl::string<> type;
};
template <int I, int Radix = 10>
struct apply
{
// All bases != 10 consider I as unsigned
typedef typename radix_convert<
Radix, static_cast<unsigned int>((Radix == 10 && I < 0) ? -I : I)
>::type converted_t;
// Prefix with '-' if negative and base 10
typedef typename mpl::if_<
mpl::bool_<(Radix == 10 && I < 0)>
, mpl::push_front<converted_t, mpl::char_<'-'> >
, mpl::identity<converted_t>
>::type::type type;
};
};
int main(int argc, char* argv[])
{
std::cout << mpl::c_str<itoa_ct::apply<12345>::type>::value << "\n";
std::cout << mpl::c_str<itoa_ct::apply<-98765>::type>::value << "\n";
std::cout << mpl::c_str<itoa_ct::apply<2009, 2>::type>::value << "\n";
std::cout << mpl::c_str<itoa_ct::apply<0xb0057, 16>::type>::value << "\n";
std::cout << mpl::c_str<itoa_ct::apply<0xffffffff, 16>::type>::value << "\n";
return 0;
}
which outputs, as expected:
12345
-98765
11111011001
b0057
ffffffff
I'm swamped with thesis-work until June, so I cannot really do much
else with this for now, but I just wanted to throw it out there. Any
thoughts? :)
Regards,
Tor Brede Vekterli
<snip>
> int main(int argc, char* argv[])
> {
> std::cout << mpl::c_str<itoa_ct::apply<12345>::type>::value << "\n";
> std::cout << mpl::c_str<itoa_ct::apply<-98765>::type>::value << "\n";
> std::cout << mpl::c_str<itoa_ct::apply<2009, 2>::type>::value << "\n";
> std::cout << mpl::c_str<itoa_ct::apply<0xb0057, 16>::type>::value << "\n";
> std::cout << mpl::c_str<itoa_ct::apply<0xffffffff, 16>::type>::value << "\n";
> return 0;
> }
>
> which outputs, as expected:
>
> 12345
> -98765
> 11111011001
> b0057
> ffffffff
>
> I'm swamped with thesis-work until June, so I cannot really do much
> else with this for now, but I just wanted to throw it out there. Any
> thoughts? :)
Whoa. Sick and twisted, but cool. I'm not sure what it's good for,
though. After all, this:
mpl::c_str<itoa_ct::apply<0xffffffff, 16>::type>::value
is just an obfuscation of:
"ffffffff"
But it sure is fun. :-)
--
Eric Niebler
BoostPro Computing
http://www.boostpro.com