std::enable_if 基于可变参数模板的存在
std::enable_if based on variadic template existence
我想创建将 ClassType 及其构造函数参数作为模板参数的对象创建器 class。
在基础上,我的代码如下所示:
template<typename ClassType, typename ... Args>
class ClassCreator : public ClassType
{
std::tuple<Args ...> args_;
public:
template <typename std::enable_if<sizeof...(Args)!=0>::type>
ClassCreator(Args ... args) : args_(std::make_tuple(args ...)), ClassType(args ...){}
template <typename std::enable_if<sizeof...(Args)==0>::type>
ClassCreator() : ClassType(){}
template <typename std::enable_if<sizeof...(Args)!=0>::type>
ClassType getObject() const
{
return ClassType(std::get<sizeof...(Args)>(args_) ... );
}
template <typename std::enable_if<sizeof...(Args)==0>::type>
ClassType getObject() const
{
return ClassType();
}
};
用std::enable_if
守卫避免std::get<0>
从空tuple
.
我将它与示例一起使用 class:
class A
{
public:
A(){}
A(int firstInt, int secondInt){}
};
int main()
{
ClassCreator<A> creatorATrivial();
ClassCreator<A, int, int> creatorA(1, 2);
A aTrivial = creatorATrivial.getObject();
A a = creatorA.getObject();
}
而且我遇到了很多错误。
我对 sizeof...
运算符的理解正确吗?
std::get<sizeof...(Args)>(args_) ...
是解压缩 tuple
的有效方法吗?
问题是SFINAE只是not an error 替换的直接上下文。在您的示例中:
template<typename ClassType, typename ... Args>
class ClassCreator : public ClassType
{
template <typename std::enable_if<sizeof...(Args)!=0>::type>
ClassCreator(Args ... args)
Args...
不在构造函数的直接上下文中,因此将立即执行替换,并且启动的函数将是 enable_if<true>::type
或 enable_if<false>::type
,后者是ill-formed。
还有这个:
return ClassType(std::get<sizeof...(Args)>(args_) ... );
是ill-formed。第二个 ...
没有要扩展的包。通常的解决方法是使用索引序列技巧。对于 C++17,我们还有 std::apply
,在本例中为:
return std::apply([](auto const&... elems){ return ClassType(elems...); },
args_);
让 class 创建者存储参数然后传递它们的最简单方法是:
template <class T>
class ClassCreator {
std::function<T()> creator;
public:
// as improvements, add perfect forwarding
template <class... Args,
std::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0>
ClassCreator(Args... args) {
creator = [=]{ return T(args...); };
}
T getObject() const {
return creator();
}
};
ClassCreator<A> creatorATrivial();
ClassCreator<A> creatorA(1, 2); // no <int, int> necessary
A aTrivial = creatorATrivial.getObject();
A a = creatorA.getObject();
我想创建将 ClassType 及其构造函数参数作为模板参数的对象创建器 class。
在基础上,我的代码如下所示:
template<typename ClassType, typename ... Args>
class ClassCreator : public ClassType
{
std::tuple<Args ...> args_;
public:
template <typename std::enable_if<sizeof...(Args)!=0>::type>
ClassCreator(Args ... args) : args_(std::make_tuple(args ...)), ClassType(args ...){}
template <typename std::enable_if<sizeof...(Args)==0>::type>
ClassCreator() : ClassType(){}
template <typename std::enable_if<sizeof...(Args)!=0>::type>
ClassType getObject() const
{
return ClassType(std::get<sizeof...(Args)>(args_) ... );
}
template <typename std::enable_if<sizeof...(Args)==0>::type>
ClassType getObject() const
{
return ClassType();
}
};
用std::enable_if
守卫避免std::get<0>
从空tuple
.
我将它与示例一起使用 class:
class A
{
public:
A(){}
A(int firstInt, int secondInt){}
};
int main()
{
ClassCreator<A> creatorATrivial();
ClassCreator<A, int, int> creatorA(1, 2);
A aTrivial = creatorATrivial.getObject();
A a = creatorA.getObject();
}
而且我遇到了很多错误。
我对 sizeof...
运算符的理解正确吗?
std::get<sizeof...(Args)>(args_) ...
是解压缩 tuple
的有效方法吗?
问题是SFINAE只是not an error 替换的直接上下文。在您的示例中:
template<typename ClassType, typename ... Args>
class ClassCreator : public ClassType
{
template <typename std::enable_if<sizeof...(Args)!=0>::type>
ClassCreator(Args ... args)
Args...
不在构造函数的直接上下文中,因此将立即执行替换,并且启动的函数将是 enable_if<true>::type
或 enable_if<false>::type
,后者是ill-formed。
还有这个:
return ClassType(std::get<sizeof...(Args)>(args_) ... );
是ill-formed。第二个 ...
没有要扩展的包。通常的解决方法是使用索引序列技巧。对于 C++17,我们还有 std::apply
,在本例中为:
return std::apply([](auto const&... elems){ return ClassType(elems...); },
args_);
让 class 创建者存储参数然后传递它们的最简单方法是:
template <class T>
class ClassCreator {
std::function<T()> creator;
public:
// as improvements, add perfect forwarding
template <class... Args,
std::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0>
ClassCreator(Args... args) {
creator = [=]{ return T(args...); };
}
T getObject() const {
return creator();
}
};
ClassCreator<A> creatorATrivial();
ClassCreator<A> creatorA(1, 2); // no <int, int> necessary
A aTrivial = creatorATrivial.getObject();
A a = creatorA.getObject();