конкатенация строк времени компиляции c ++ с использованием boost-mpl - PullRequest
5 голосов
/ 18 мая 2011

Я пытаюсь объединить строки во время компиляции, используя boost-mpl, но получаю ошибки от gcc. Вот образец -

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;
};

Итак, я пытаюсь достичь:

converter<int,char,int> == "ici\0" // true. 

Проблема в том, что приведенный выше код в gcc выдает следующие ошибки:

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’

Может ли кто-нибудь указать на проблему с приведенным выше кодом и объяснить правильный способ сделать это? Спасибо

РЕДАКТИРОВАТЬ 1: исправлено форматирование и несколько опечаток

РЕДАКТИРОВАТЬ 2: После Lambdageek, предложение Энди код компилируется, но когда я пытаюсь распечатать результат

int main(int argc, char** argv) {
    cout << mpl::c_str< converter<int,char>::value >::value << endl;
    return 0;
}

, компилятор жалуется -

/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::string<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

Я признаю, что я очень плохо знаком с шаблонным программированием, поэтому уверен, что проблема должна быть чем-то элементарным. Спасибо за помощь

EDIT 3: изменена строка push_back в структуре конвертера.

Ошибки:

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’

Ответы [ 3 ]

3 голосов
/ 18 мая 2011

ОК, согласно вашим последним изменениям, я вижу здесь несколько проблем.

Во-первых, вы можете использовать mpl::push_back для добавления элемента в последовательность.Теперь вы объединяете две последовательности.Я изменил тип type<>::value на mpl::char_, затем изменил порядок аргументов mpl::push_back (сначала последовательность, затем элемент).Кроме того, вы должны использовать push_front, а не push_back в этом коде.Наконец, я добавил ::type после push_front, потому что вы должны извлечь фактический тип здесь.Вот код для справки:

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;
};

Теперь этот код работает должным образом:

int
main (void)
{
        cout << mpl::c_str< converter<int,char>::value >::value << endl;
        return 0;
}

(печать ic).

2 голосов
/ 18 мая 2011

Вам необходимо использовать ключевое слово typename:

typedef mpl::push_back< typename type<A>::value, typename converter<B,C,D>>:value >::type value;

При доступе к вложенной typedef шаблона, который создается с помощью аргументов шаблона, вы нужно помочь C ++ решить, относится ли вложенное имя к методу / полю или к определению вложенного типа. Если вы ничего не говорите, C ++ будет считать, что это имя поля. Если вы скажете typename, это примет вложенная вещь - это тип.

2 голосов
/ 18 мая 2011

Поможет ли добавить ключевое слово typename, чтобы сообщить компилятору, что ::value - это тип?

struct converter {
    typedef mpl::push_back< typename type<A>::value, typename converter<B,C,D>::value > value ;
};
...