2014-12-11 3 views
0

У меня есть следующее (неполный, не работоспособное) определение:Захвата параметр шаблона переменного числа шаблонных аргументов

template<typename T, std::function<Args(Context&)>... Funcs> 
struct constructor 
{ 
    T construct(Context& ctx) 
    { 
     return T(Funcs(ctx)...); 
    } 
}; 

То, что я хочу, это шаблонный класс - первый аргумент сконструированного типа, и все следующие функции которые будут вызываться, пользовательские шаблоны с std::function s, которые затем вызывают для создания значений для конструктора типа T.

Я не вижу возможности заставить этот код работать, а также убирать возвращаемые типы функций. Я хочу, чтобы пользователь использовал его следующим образом:

std::function<int(Context&)> ind = [](Context&) {return 2;}; 
Constructor<int, ind> c; 
// c.construct(...) returns 2 by calling the constructor int(int) with argument 
//      ind(ctx) - which returns 2. 
+0

Я не могу точно сказать, что вы хотите. Можете ли вы объяснить более подробно? –

+0

Я добавил немного информации, возможно, это делает ее более ясной. – WorldSEnder

+0

Да, но ваша 'конструкция', вероятно, предназначена для использования' return'. –

ответ

2

Это может быть примерно то, что вы ищете. Имейте в виду, что параметр std::function не может быть параметром шаблона.

template <typename R> using Generator = std::function<R (Context&)>; 

template <typename T, typename Generators, std::size_t... Is> 
T constructImpl(Context& ctx, const Generators& generators, 
       std::index_sequence<Is...>) { 
    return T(std::get<Is>(generators)(ctx)...); 
} 

template <typename T, typename... Args> 
class Constructor { 
    std::tuple<Generator<Args>...> generators; 

public: 
    Constructor(Generator<Args>... generators) 
     : generators(std::move(generators)...) 
    {} 

    T construct(Context& ctx) { 
     return constructImpl<T>(ctx, generators, 
           std::index_sequence_for<Args...>()); 
    } 
}; 

Использование:

Constructor<int, int> c([](Context&) { return 2; }); 
int i = c.construct(context); 
assert(i == 2); 
+1

Можем ли мы также реализовать 'make_Constructor' так, чтобы' auto c = make_Constructor ([] (Context &) {return 2;}); 'работает, требуя меньше аргументов явного шаблона? – aschepler

+0

Да, используя функции в качестве аргументов шаблона и используя 'decltype' или' std :: result_of', чтобы определить их тип возврата. –

0

Я думаю, что ваш Construct может быть просто функцией:

template <typename T, typename... Funcs> 
T construct(Context& ctx, Funcs... funcs) { 
    return T(funcs(ctx)...); 
} 

, использование которых может быть в вашем примере может быть:

int x = construct<int>(ctx, [](Context&) { return 2; }); 
1

Типы не могут зависеть от данных времени выполнения.

Для того, чтобы позвонить в std::function<X(Y)>, необходимо их время от времени. Таким образом, ваш тип не может зависеть от std::function<X(Y)>, поэтому тип не может использоваться в качестве параметра шаблона.

Теперь это может зависеть от указателя на глобальный объект: это достаточно интересно, если не указано время выполнения до C++.

Как таковой, ваш дизайн в основном ошибочен.

Если вы хотите функцию таким образом, что она возвращает 2, это работает:

template<class...ignored> 
struct Constructor { 
    template<class... also_ignored> 
    Constructor(also_ignored&&...) {} 
    template<class... also_ignored> 
    int construct(also_ignored&&...) { return 2; } 
}; 

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

Если вы хотите больше энергии, мы могли бы сделать это:

template<class T, class... Functors> 
struct Constructor { 

    T construct(Context& ctx) { 
    return T(Functors{}(ctx)...); 
    } 
}; 

в этом случае вам необходимо апатридов функциональные объекты:

struct ind { int operator()(Context&)const{return 2;} }; 

очень нравится, как std::map требует апатридов объектов сравнения.

Если объекты вашей функции требуют состояния, вам необходимо сохранить их копию для Constructor для доступа (возможно, в пределах Constructor), и вам может понадобиться трюк для кортежей и индексов для их хранения. («indexs trick» - полезный Google)

+0

Спасибо за разъяснение ПОЧЕМУ он не работает. Последние бит немного ... странно. Я четко заявляю, что пользователь должен передать функции, которые затем используются для создания объектов, которые затем используются для создания конечного значения. Я не совсем понимаю, какова точка вашего примера, примеры выбраны как простые, в этом случае у меня есть одна функция (которая всегда возвращает 2) для создания int, передаваемого конструктору int. Скажите мне, где вы потерялись, поэтому я могу привести лучший пример в следующий раз. – WorldSEnder

+0

@worldsender Я задал несколько вопросов в качестве комментария к вашему оригинальному вопросу. У вас есть '...' и 'Context' undefined в вашем коде. Они могут быть связаны. Какой «Контекст» есть и как вы собираетесь его использовать, может помочь. – Yakk

Смежные вопросы