[Boost-users] [concept check][mpl] (Conditional) Concept checking for functions

18 views
Skip to first unread message

Jesse Perla

unread,
Mar 29, 2009, 4:17:19 PM3/29/09
to Boost Users Mailing List
I have a variety of user defined function objects that I will need to call.  Take the following examples:
template<int N1, int N2 = 0>
struct Func1{ double operator()(boost::array<double, N1>& x1, boost::array<double, N2>& x2){...}};

template<int N1>
struct Func2{ double operator()(boost::array<double, N1>& x){...}};

With a function such as 

template<int N1,
               int N2 = 0,
               class F = boost::function<double (boost::array<double, N1>& x1, boost::array<double, N2>& x2)>
class DPP{ void solve(){...... uses F...to be discussed} }; 

I have a few questions:
1) Is there a relatively easy way to use boost concept check to verify that F follows the first function signature so that I can detect compile time the problem?  I can't figure out how to do it from the concept check docs, and they say they are out of date.
Usage I want to check in the instantiation of DPP:
      F f;
      f(boost::array<double, N1>& x1, boost::array<double, N2>& x2)


2) I want the user to be able to pass in a simplified function type if N2 = 0

I assume that to call the actual function I would have some kind of impl function with partial specialization such as:
template<bool use_simplified, int N1, int N2>
struct use_f_impl();

template<int N1, int N2>
struct use_f_impl<true, N1, N2>{
   static double use_f()
   {
      STATIC_ASSERT(N2 == 0);
       F f;
      boost::array<double, N1> x;
       return f(x);
   }
};


template<int N1, int N2>
struct use_f_impl<false, N1, N2>{
   static double use_f()
   {
       F f;
      boost::array<double, N1> x1;
      boost::array<double, N2> x2;
       return f(x1, x2);
   }
};

And then in my solve() function I go:
  double val = use_f<(N2 == 0, N1, N2)>::use_f();

Is this the right idiom, pattern, etc?  Do I need to use the struct with a static function since function templates don't have partial specialization?

3) Now what if I want to do a concept check on the F passed into DPP?  It has to be conditional on the N2 value now.  How would I do this?


4) Lets say that I don't want to force them to use the simplified version of the function signature if they don't want to.
Can I automatically detect the signature and put it into a flag integer in the class?
i.e. inside of the DPP class:
static bool use_simple = IsSimple<F>::value;
Then pass in the use_simple value when calling use_f_impl.
If so, what would the IsSimple metafunction look like and can concept check help?

Thanks,
Jesse

Jesse Perla

unread,
Mar 29, 2009, 4:32:28 PM3/29/09
to Boost Users Mailing List
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?

template<class F>
class
{
        typedef CheckFunctionCompatible<boost::function<double (double)>, F> test_F_compatibility;
};


Of course, this wouldn't work for detecting the signature of the function, but that is a 2nd order feature for me.  Of course, this also assumes that F can be constructed with no parameters, but this also might be reasonable for me if there is no better solution.

-Jesse

Andy Stevenson

unread,
Mar 29, 2009, 6:21:46 PM3/29/09
to boost...@lists.boost.org
Hi,

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

Eric Niebler

unread,
Mar 29, 2009, 11:58:09 PM3/29/09
to boost...@lists.boost.org
Andy Stevenson wrote:
> Hi,
>
> I recall some discussion of there being an mpl::string template.....
> Can't see it in the mpl library. Is it elsewhere?

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

Ovanes Markarian

unread,
Mar 30, 2009, 6:53:19 AM3/30/09
to boost...@lists.boost.org
Eric,

I would be interested in that too. I already had to code around in a project, to make smth. similar.


Would be nice to have it in MPL. Many thanks,
Ovanes

Andy Stevenson

unread,
Mar 30, 2009, 8:07:18 PM3/30/09
to boost...@lists.boost.org
Thanks Eric.... would be a useful addition to mpl I think at some point.
Great for DSLs which is how I intend to use it.

Andy

Steven Watanabe

unread,
Mar 30, 2009, 10:41:50 PM3/30/09
to boost...@lists.boost.org
AMDG

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

Jesse Perla

unread,
Mar 31, 2009, 9:06:34 AM3/31/09
to boost...@lists.boost.org
On Mon, Mar 30, 2009 at 10:41 PM, Steven Watanabe <watan...@gmail.com> wrote:
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

Steven,
Thanks as always.

Is there any way to turn this into a metafunction predicate?  I don't mind hardcoding a specific boost::function predicate for each function I am testing, which might be a better idea anyways for clarity.

Thanks,
Jesse

Eric Niebler

unread,
Apr 2, 2009, 7:37:14 PM4/2/09
to boost...@lists.boost.org, Aleksey Gurtovoy
Ovanes Markarian wrote:
> Eric Niebler wrote:
>> Andy Stevenson wrote:
>>>
>>> I recall some discussion of there being an mpl::string
>>> template..... Can't see it in the mpl library. Is it elsewhere?
>>
>> 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
>
> I would be interested in that too. I already had to code around in a
> project, to make smth. similar.
>
> Would be nice to have it in MPL. Many thanks,

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

Eric Niebler

unread,
Apr 6, 2009, 2:08:58 AM4/6/09
to boost...@lists.boost.org
>>> Andy Stevenson wrote:
>>>>
>>>> I recall some discussion of there being an mpl::string
>>>> template..... Can't see it in the mpl library. Is it elsewhere?

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.

Noah Roberts

unread,
Apr 7, 2009, 12:46:50 PM4/7/09
to boost...@lists.boost.org
Eric Niebler wrote:
>>>> Andy Stevenson wrote:
>>>>>
>>>>> I recall some discussion of there being an mpl::string
>>>>> template..... Can't see it in the mpl library. Is it elsewhere?
>
> 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?

Eric Niebler

unread,
Apr 7, 2009, 1:21:58 PM4/7/09
to boost...@lists.boost.org
Noah Roberts wrote:
> Eric Niebler wrote:
>>>>> Andy Stevenson wrote:
>>>>>>
>>>>>> I recall some discussion of there being an mpl::string
>>>>>> template..... Can't see it in the mpl library. Is it elsewhere?
>>
>> 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

rai...@macrohmasheen.com

unread,
Apr 7, 2009, 1:58:39 PM4/7/09
to boost...@lists.boost.org
L$$m$Ll$l$l$


Sent from my Verizon Wireless BlackBerry

Dominique Devienne

unread,
Apr 7, 2009, 3:54:20 PM4/7/09
to boost...@lists.boost.org
On Tue, Apr 7, 2009 at 12:21 PM, Eric Niebler <er...@boost-consulting.com> wrote:
> multi-character literals give a nicer compile-time string interface.
> // With mpl::string
> mpl::string<'hell','o wo','rld'>

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

[1] http://publib.boulder.ibm.com/infocenter/lnxpcomp/v7v91/index.jsp?topic=/com.ibm.vacpp7l.doc/language/ref/clrc02ccon.htm

[2] http://bytes.com/groups/c/739845-multi-character-constant

Eric Niebler

unread,
Apr 7, 2009, 4:26:25 PM4/7/09
to boost...@lists.boost.org
Dominique Devienne wrote:
> On Tue, Apr 7, 2009 at 12:21 PM, Eric Niebler <er...@boost-consulting.com> wrote:
>> multi-character literals give a nicer compile-time string interface.
>> // With mpl::string
>> mpl::string<'hell','o wo','rld'>
>
> 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

"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

Noah Roberts

unread,
Apr 8, 2009, 12:09:52 PM4/8/09
to boost...@lists.boost.org

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.

Ovanes Markarian

unread,
Apr 8, 2009, 12:21:14 PM4/8/09
to boost...@lists.boost.org
On Wed, Apr 8, 2009 at 6:09 PM, Noah Roberts <robert...@gmail.com> wrote:

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.

I agree with Noah.

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.


Many thanks,
Ovanes

Eric Niebler

unread,
Apr 8, 2009, 12:57:27 PM4/8/09
to boost...@lists.boost.org
Ovanes Markarian wrote:

> Noah Roberts wrote:
>> 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!'>.

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

Eric Niebler

unread,
Apr 8, 2009, 1:08:49 PM4/8/09
to boost...@lists.boost.org
Noah Roberts wrote:
> 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.

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

Ovanes Markarian

unread,
Apr 8, 2009, 1:19:52 PM4/8/09
to boost...@lists.boost.org
On Wed, Apr 8, 2009 at 6:57 PM, Eric Niebler <er...@boostpro.com> 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??? I just looked over your tests and did not get immediately that these all use char test sequences.

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;


Would be cool to find a solution of really passing strings like:

typedef string<"abcd efg..">     some_other_type;



Regards,
Ovanes
 

Noah Roberts

unread,
Apr 8, 2009, 1:44:05 PM4/8/09
to boost...@lists.boost.org
Eric Niebler wrote:
> Noah Roberts wrote:
>> 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.
>
> 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.

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.

Eric Niebler

unread,
Apr 8, 2009, 1:51:41 PM4/8/09
to boost...@lists.boost.org
Ovanes Markarian wrote:

> 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???

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. ;-)

Eric Niebler

unread,
Apr 8, 2009, 2:16:51 PM4/8/09
to boost...@lists.boost.org
Noah Roberts wrote:
> Eric Niebler wrote:
>> 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.
>
> 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.

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

unread,
Apr 8, 2009, 3:42:21 PM4/8/09
to boost...@lists.boost.org
On Wed, Apr 8, 2009 at 7:51 PM, Eric Niebler <er...@boost-consulting.com> wrote:
Ovanes Markarian wrote:

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???

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.
Yes, sure. It is already late in Munich and I have headache. I meant exactly that.
 


I just looked over your tests and did not get immediately that these
all use char test sequences.

I don't follow you.
Sorry again. I mean that your tests are based on 4-char literals, which I did not pay attention.



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.
:) But for my special use case that was enough. I defenitely share your opinion, that a library implementation should be more flexible, than my special use case impl was. On the other hand I too oft see programmers which are ignorant and even don't give a chance to a great approach. I can imagine their reaction when seeing:

typdef mpl::string<'some', 'cool', 'type'>    compile_time_string;
 


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. ;-)
Would be nice to get there ;)


Cheers,
Ovanes

Noah Roberts

unread,
Apr 8, 2009, 4:33:44 PM4/8/09
to boost...@lists.boost.org
Eric Niebler wrote:
>>>> Andy Stevenson wrote:
>>>>>
>>>>> I recall some discussion of there being an mpl::string
>>>>> template..... Can't see it in the mpl library. Is it elsewhere?
>
> 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.
>

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();

Eric Niebler

unread,
Apr 8, 2009, 4:39:22 PM4/8/09
to boost...@lists.boost.org
Noah Roberts wrote:
> Eric Niebler wrote:
>>>>> Andy Stevenson wrote:
>>>>>>
>>>>>> I recall some discussion of there being an mpl::string
>>>>>> template..... Can't see it in the mpl library. Is it elsewhere?
>>
>> 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.
>
> Visual Studio 2005 hates it.

<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

Noah Roberts

unread,
Apr 8, 2009, 5:24:15 PM4/8/09
to boost...@lists.boost.org
Eric Niebler wrote:
> Noah Roberts wrote:
>> Eric Niebler wrote:
>>>>>> Andy Stevenson wrote:
>>>>>>>
>>>>>>> I recall some discussion of there being an mpl::string
>>>>>>> template..... Can't see it in the mpl library. Is it elsewhere?
>>>
>>> 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.
>>
>> Visual Studio 2005 hates it.
>
> <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.

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.

Eric Niebler

unread,
Apr 8, 2009, 5:59:01 PM4/8/09
to boost...@lists.boost.org
Noah Roberts wrote:
> 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

Eric Niebler

unread,
Apr 10, 2009, 5:47:46 PM4/10/09
to boost...@lists.boost.org
Eric Niebler wrote:
> 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).

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. :-(

Eric Niebler

unread,
Apr 11, 2009, 2:36:11 AM4/11/09
to boost...@lists.boost.org
Eric Niebler wrote:
> Eric Niebler wrote:
>> 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).
>
> 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.

Aleksey Gurtovoy

unread,
Apr 12, 2009, 3:43:27 AM4/12/09
to boost...@lists.boost.org
On Sat, 11 Apr 2009 01:36:11 -0500, Eric Niebler <er...@boostpro.com> wrote:
> 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

Noah Roberts

unread,
Apr 13, 2009, 11:45:34 AM4/13/09
to boost...@lists.boost.org
Eric Niebler wrote:
> Eric Niebler wrote:
>> Eric Niebler wrote:
>>> 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).
>>
>> 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.
>
No problem.

Now someone just needs to make format<> :P

Tor Brede Vekterli

unread,
Apr 17, 2009, 1:37:11 AM4/17/09
to boost...@lists.boost.org
On Mon, Apr 13, 2009 at 5:45 PM, Noah Roberts <robert...@gmail.com> wrote:
> Eric Niebler wrote:
>>
>> Eric Niebler wrote:
>>>
>>> Eric Niebler wrote:
>>>>
>>>> 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).
>>>
>>> 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.
>>
> No problem.
>
> 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

Eric Niebler

unread,
Apr 20, 2009, 8:31:29 PM4/20/09
to boost...@lists.boost.org
Tor Brede Vekterli wrote:

> Noah Roberts wrote:
>> 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 ;)

<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

Reply all
Reply to author
Forward
0 new messages