首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >捕获可变模板参数的模板参数

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

Stack Overflow用户
提问于 2014-12-11 15:45:10
回答 3查看 320关注 0票数 0

我有以下定义(不完整,不起作用):

代码语言:javascript
复制
template<typename T, std::function<Args(Context&)>... Funcs>
struct constructor
{
    T construct(Context& ctx)
    {
        return T(Funcs(ctx)...);
    }
};

我想要的是一个模板化的类-第一个参数是构造的类型,下面的所有函数都是要调用的函数,然后调用带有std::function的用户模板来为T类型的构造函数生成值。

除了捕获函数的返回类型之外,我看不出有可能使这段代码工作。我希望用户像这样使用它:

代码语言:javascript
复制
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.
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-12-11 16:01:54

这大概就是你要找的东西。请记住,std::function不能成为模板参数。

代码语言:javascript
复制
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...>());
   }
};

用法:

代码语言:javascript
复制
Constructor<int, int> c([](Context&) { return 2; });
int i = c.construct(context);
assert(i == 2);
票数 2
EN

Stack Overflow用户

发布于 2014-12-11 16:56:09

类型不能依赖于运行时数据。

调用std::function<X(Y)>需要运行时数据。因此,您的类型不能依赖于std::function<X(Y)>,因此不能将该类型用作模板参数。

现在,它可以依赖于指向全局对象的指针:有趣的是,就C++而言,这并不是运行时状态。

因此,您的设计是有根本缺陷的。

如果您想要一个返回2的函数,这是可行的:

代码语言:javascript
复制
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,因为这是不合法的。但是,将其从类型签名中删除并不重要。

如果你想要更多的能量,我们可以这样做:

代码语言:javascript
复制
template<class T, class... Functors>
struct Constructor {

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

在这种情况下,您需要无状态函数对象:

代码语言:javascript
复制
struct ind { int operator()(Context&)const{return 2;} };

就像std::map需要无状态比较对象一样。

如果您的函数对象需要状态,那么您需要存储它们的副本,以便Constructor访问(可能在Constructor中),并且可能需要元组和索引技巧来存储它们。(“索引技巧”是一个有用的谷歌)

票数 1
EN

Stack Overflow用户

发布于 2014-12-11 16:13:15

我认为您的Construct可以只是一个函数:

代码语言:javascript
复制
template <typename T, typename... Funcs>
T construct(Context& ctx, Funcs... funcs) {
    return T(funcs(ctx)...);
}

在您的示例中,其用法可以是:

代码语言:javascript
复制
int x = construct<int>(ctx, [](Context& ) { return 2; });
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27426805

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档