c++ compile-time string concatenation using boost-mpl
I'm trying to concatenate strings at compile-time using boost-mpl but am getting errors from gcc. Here's the sample -
using namespace boost;
using namespace std;
template<class A>
struct type {};
template<>
struct type<int> {
typedef mpl::string < 'i' > value;
};
template<>
struct type<char> {
typedef mpl::string < 'c' > value;
};
struct empty {
};
template<class A, class B, class C, class D>
struct converter;
template<class A, class B = empty, class C = empty, class D = empty>
struct converter {
typedef mpl::push_back< type<A>::value, converter<B,C,D>::value >::type value ;
};
template<>
struct converter<empty, empty, empty, empty> {
typedef mpl::string < '\0' > value;
};
So, what i'm trying to achieve is :
converter<int,char,int> == "ici\0" // true.
Problem is that the above code in gcc throws the following errors:
main.cpp:37: error: type/value mismatch at argument 1 in template parameter list for ‘template<class Sequence, class T> struct boost::mpl::push_back’
main.cpp:37: error: expected a type, got ‘type::value’
main.cpp:37: error: type/value mismatch at argument 2 in template parameter list for ‘template<class Sequence, class T> struct boost::mpl::push_back’
main.cpp:37: error: expected a type, got ‘converter::value’
Could anyone point out the problem with the above code and explain the right way to do it ? Thanks
EDIT 1: corrected formatting and few typos
EDIT 2: After Lambdageek, Andy's suggestion the code does compile but when i try to print the result
int main(int argc, char** argv) {
cout << mpl::c_str< converter<int,char>::value >::value << endl;
return 0;
}
, compiler complains -
/usr/local/include/boost/mpl/string.hpp:534: instantiated from ‘boost::mpl::c_str<boost::mpl::push_back<boost::mpl::string<105, 0, 0, 0, 0, 0, 0, 0>, boost::mpl::push_back<boost::mpl::string<105, 0, 0, 0, 0, 0, 0, 0>, boost::mpl::string<0, 0, 0, 0, 0, 0, 0, 0> > > >’
main.cpp:49: instantiated from here
/usr/local/include/boost/mpl/string.hpp:228: error: ‘value’ is not a member of ‘boost::mpl::push_back<boost::mpl::string<105, 0, 0, 0, 0, 0, 0, 0>, boost::mpl::string<0, 0, 0, 0, 0, 0, 0, 0> >’
/usr/local/include/boost/mpl/string.hpp: In instantiation of ‘boost::mpl::c_str<boost::mpl::push_back<boost::mpl::string<105, 0, 0, 0, 0, 0, 0, 0>, boost::mpl::push_back<boost::mpl::string<105, 0, 0, 0, 0, 0, 0, 0>, boost::mpl::string<0, 0, 0, 0, 0, 0, 0, 0> > > >’:
main.cpp:49: instantiated from here
/usr/local/include/boost/mpl/string.hpp:548: error: no type named ‘value_type’ in struct boost::mpl::push_back<boost::mpl::string<105, 0, 0, 0, 0, 0, 0, 0>, boost::mpl::push_back<boost::mpl::str开发者_C百科ing<105, 0, 0, 0, 0, 0, 0, 0>, boost::mpl::string<0, 0, 0, 0, 0, 0, 0, 0> > >’
main.cpp: In function ‘int main(int, char**)’:
main.cpp:49: error: ‘value’ is not a member of ‘boost::mpl::c_str<boost::mpl::push_back<boost::mpl::string<105, 0, 0, 0, 0, 0, 0, 0>, boost::mpl::push_back<boost::mpl::string<105, 0, 0, 0, 0, 0, 0, 0>, boost::mpl::string<0, 0, 0, 0, 0, 0, 0, 0> > > >’
make[2]: *** [build/Debug/GNU-Linux-x86/main.o] Error 1
make[1]: *** [.build-conf] Error 2
I admit that i'm very new to template programming, so am sure the problem must be something elementary. Thanks for all the help
EDIT 3: Changed the push_back line in converter struct.
Errors:
main.cpp:41: error: type ‘boost::mpl::push_back<typename type<A>::value, typename converter<B, C, D, empty>::value>’ is not derived from type ‘converter<A, B, C, D>’
main.cpp:41: error: expected ‘;’ before ‘value’
OK, as per your final edits, I see several problems here.
First, you can use mpl::push_back
to add an element to a sequence. Now you're concatenating two sequences. I changed the type of type<>::value
to mpl::char_
, then changed the order of the mpl::push_back
arguments (first the sequence, then the element). Also, you have to use push_front
, not push_back
in this code. Finally, I added a ::type
after the push_front
, because you have to extract the actual type here. Here is the code for reference:
using namespace boost;
using namespace std;
template<class A>
struct type {};
template<>
struct type<int> {
typedef mpl::char_ < 'i' > value;
};
template<>
struct type<char> {
typedef mpl::char_ < 'c' > value;
};
struct empty {
};
template<class A, class B, class C, class D>
struct converter;
template<class A, class B = empty, class C = empty, class D = empty>
struct converter {
typedef typename mpl::push_front< typename converter<B,C,D>::value, typename type<A>::value >::type value ;
};
template<>
struct converter<empty, empty, empty, empty> {
typedef mpl::string < '\0' > value;
};
Now this code works as expected:
int
main (void)
{
cout << mpl::c_str< converter<int,char>::value >::value << endl;
return 0;
}
(prints ic
).
Does it help to add the typename
keyword, to tell the compiler that ::value
is a type?
struct converter {
typedef mpl::push_back< typename type<A>::value, typename converter<B,C,D>::value > value ;
};
You need to use the typename
keyword:
typedef mpl::push_back< typename type<A>::value, typename converter<B,C,D>>:value >::type value;
When accessing a nested typedef of a template that is instantiated with your template arguments, you
need to help C++ decide whether the nested name refers to a method/field or to a nested type definition.
If you don't say anything, C++ will assume it's a field name. If you say typename
it will assume the
nested thing is a type.
精彩评论