Используя boost :: mpl, как я могу узнать, сколько шаблонных классов не является «пустыми», и вызвать некоторый макрос с этим номером? - PullRequest
1 голос
/ 09 декабря 2011

Я хочу вызвать макрос с некоторыми аргументами, зависящими от результата boost::mpl::eval_if (или аналогичной функции), который может дать количество пустых аргументов шаблона. Скажем, у нас есть псевдокод, подобный следующему:

struct EmptyType {  };
template<class arg1=EmptyType, class arg2=EmptyType, class arg3=EmptyType>
class my_class
{
     eval_if<is_not_same<arg1, EmptyType>, FILL_MY_CLASS_DEFINE(1)> else      
     eval_if<is_not_same<arg2, EmptyType>, FILL_MY_CLASS_DEFINE(2)> else
     eval_if<is_not_same<arg3, EmptyType>, FILL_MY_CLASS_DEFINE(3)>;
};

Я пытаюсь заполнить свой класс некоторым содержанием, в зависимости от того, сколько аргументов EmptyType. Интересно, как это можно сделать в C ++ 03 через Boost.MPL / Preprocessor или какую-либо другую библиотеку Boost?

Ответы [ 3 ]

2 голосов
/ 09 декабря 2011

Вам не нужен препроцессор или mpl.Вам нужна частичная специализация:

Редактировать Это работает на C ++ 03, смотрите вживую: https://ideone.com/6MaHJ

#include <iostream>
#include <string>

struct EmptyType {  };

template<class  arg1=EmptyType, class arg2=EmptyType, class arg3=EmptyType>
class my_class
{
    // FILL_MY_CLASS_DEFINE(3)
};
template<class  arg1, class arg2>
class my_class<arg1,arg2,EmptyType>
{
    // FILL_MY_CLASS_DEFINE(2)
};
template<class  arg1>
class my_class<arg1,EmptyType,EmptyType>
{
    // FILL_MY_CLASS_DEFINE(1)
};
template<>
class my_class<EmptyType,EmptyType,EmptyType>
{
    // FILL_MY_CLASS_DEFINE(0)
};

int main(int argc, const char *argv[])
{
    my_class<std::string, double, int> a;
    my_class<std::string, int> b;
    my_class<void> c;

    return 0;
}
1 голос
/ 09 декабря 2011

Вы ищете вариадические шаблоны?

#include <tuple>
#include <iostream>
#include <string>

template <typename... Arg>
struct my_class
{
    // getting the size of the argument list:
    enum { size = sizeof...(Arg) }; // in absense of static fields with initializers...

    // demo filling the struct with data:
    std::tuple<Arg...> arg_data;
    my_class(Arg&&... a) : arg_data(std::forward<Arg>(a)...) { }
};

int main(int argc, const char *argv[])
{
    my_class<std::string, int> a("hello world", 42);

    std::cout << "size: " << a.size << std::endl;
    std::cout << "last: " << std::get<a.size-1>(a.arg_data) << std::endl;

    return 0;
}

Выход:

size: 2
last: 42
0 голосов
/ 16 января 2012

Когда у вас много аргументов шаблона, частичная специализация может быть непрактичной и подверженной ошибкам. Код ниже будет делать то, что вы хотите, но, как уже упоминалось в других ответах, это не всегда лучший способ продолжить.

#include <boost/mpl/count_if.hpp>
#include <boost/mpl/not.hpp>
#include <boost/type_traits/is_same.hpp>

using boost::is_same;
using boost::mpl::_;
using boost::mpl::not_;
using boost::mpl::count_if;

#define FILL_MY_CLASS_DEFINE(x) static const int __x__ = x // an example, watch out: no semicolon at the end

struct EmptyType {  };
template<class arg1=EmptyType, class arg2=EmptyType, class arg3=EmptyType>
class my_class
{
    // count the types which are not equal to EmptyType
    static const long NonEmptyCount = count_if<type, not_<is_same<_, EmptyType> > >::value;
    // invoke a macro with an argument
    FILL_MY_CLASS_DEFINE(NonEmptyCount);
};
...