捕获可变参数模板参数的模板参数

时间:2014-12-11 15:45:11

标签: c++ templates c++11

我有以下(不完整,不工作)的定义:

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

我想要的是一个模板化的类 - 第一个参数是构造类型,所有后面都是要调用的函数,带有std::function的用户模板然后被调用以生成类型构造函数的值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.

3 个答案:

答案 0 :(得分: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 :(得分: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; }
};

这将通过您的OP中描述的单元测试,但您无法将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内),您可能需要使用元组和索引技巧来存储它们。 (“索引技巧”是一个有用的谷歌)

答案 2 :(得分: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; });