C++11 为什么我的可变模板参数验证器拒绝在编译时求值?
我有一个递归变量模板函数,可以用来在编译时计算它的参数,以确保它们都不大于指定的最大值:C++11 为什么我的可变模板参数验证器拒绝在编译时求值?,c++11,variadic-templates,constexpr,perfect-forwarding,static-assert,C++11,Variadic Templates,Constexpr,Perfect Forwarding,Static Assert,我有一个递归变量模板函数,可以用来在编译时计算它的参数,以确保它们都不大于指定的最大值: #include <type_traits> // base-case template <int MaxVal, typename T> constexpr T returnZeroIffValuesAreNotTooBig(const T t) { return (t>MaxVal)?1:0; } // recursive-case templ
#include <type_traits>
// base-case
template <int MaxVal, typename T>
constexpr T returnZeroIffValuesAreNotTooBig(const T t)
{
return (t>MaxVal)?1:0;
}
// recursive-case
template <int MaxVal, typename T, typename... Rest> constexpr T returnZeroIffValuesAreNotTooBig(const T t, Rest&&... rest)
{
return returnZeroIffValuesAreNotTooBig<MaxVal>(t)
+ returnZeroIffValuesAreNotTooBig<MaxVal>(std::forward<Rest>(rest)...);
}
int main(int argc, char ** argv)
{
static_assert(returnZeroIffValuesAreNotTooBig<6>(1,2,3)==0, "compiles (as expected)");
static_assert(returnZeroIffValuesAreNotTooBig<6>(1,2,3,4,5,6,7)==0, "generates compile-time error (as expected, because one of the args is greater than 6)");
return 0;
}
#包括
//基本情况
模板
constexpr T returnzeroiffvaluesarenotobig(const T)
{
返回值(t>MaxVal)?1:0;
}
//递归案例
模板constexpr T returnzeroiffvaluesarenottobig(const T,Rest&…Rest)
{
返回ReturnZeroIffValuesRenotObig(t)
+returnZeroIffValuesRenotToBig(标准::向前(剩余)…);
}
int main(int argc,字符**argv)
{
静态断言(returnZeroiffValuesRenotToBig(1,2,3)=0,“编译(如预期)”;
static_assert(returnzeroiffvaluesarenottobig(1,2,3,4,5,6,7)=0,“生成编译时错误(如预期,因为其中一个参数大于6)”;
返回0;
}
。。。到目前为止,一切都很好,所有这些对我来说都很好
现在我想在类的可变构造函数中使用该函数:
template<int MaxVal> class MyClass
{
public:
template<typename ...Vals> constexpr explicit MyClass(Vals&&... vals)
{
// verify at compile-time that all values in (vals) are <= MaxVal
static_assert(returnZeroIffValuesAreNotTooBig<MaxVal>(std::forward<Vals>(vals)...)==0, "why doesn't this compile?");
}
};
int main(int argc, char ** argv)
{
MyClass<5> b(1,2,3,4); // should compile, but doesn't!?
return 0;
}
模板类MyClass
{
公众:
模板constexpr显式MyClass(VAL&…VAL)
{
//在编译时验证(VAL)中的所有值是否完美转发是无罪的
正如Caramiriel所指出的,您不能在static\u assert()测试中使用函数参数
我知道构造函数是constexpr
,但是constexpr
构造函数(与任何其他constexpr
函数一样)可以根据情况在编译时或运行时执行
因此,在运行时使用可能已知的值进行static\u assert()
测试是错误的
此外,在你的特殊情况下
MyClass<5> b(1,2,3,4);
在这种情况下,还可以将static_assert()
放在类的主体中,而不一定放在构造函数的主体中
2) 将vals…
作为模板参数传递给std::integer_序列
(仅从C++14开始提供,但用C++11中的自定义类替换它很简单)构造函数参数
如下所示(注意:代码未测试)
模板类MyClass
{
公众:
模板
constexpr MyClass(std::integer\u sequence const&)
{
//在编译时验证(VAL)中的所有值你的returnZeroiffValuesRenotToBig
函数是否应该返回一个int
?如果我理解正确,就是你不能在static\u assert
调用中使用函数参数:@Someprogrammerdude我可以将其更改为返回一个int,但这似乎并不能解决当前的问题(在实践中,typename T在任何情况下都是int或类似的)嗯…(2)可以工作,但需要C++14(在main()中的对象的声明站点也需要更多的键入;在我的实际软件中有许多这样的声明,所以我希望尽量减少它们的冗长性)。(1),如果我理解正确,将使参数成为MyClass类型的一部分,这使得将带有一组参数的MyClass分配给另一个MyClass非常困难。也许我只需要满足于运行时检查:(你是对的:(1)不同的VAL有不同的类型…
;因此,我更喜欢这种解决方案(2) ;C++14问题可以通过自定义结构得到很好的解决;例如:template struct foo{};MyClass b(foo);
我认为它不会太冗长;您还可以创建make_MyClass()
函数:template constepr MyClass make_MyClass(){return std::integer_sequence{};}/*/auto b=make_MyClass();
MyClass<5> b(1,2,3,4);
template<int MaxVal, int ... vals> class MyClass
{
public:
constexpr MyClass ()
{
// verify at compile-time that all values in (vals) are <= MaxVal
static_assert(returnZeroIffValuesAreNotTooBig<MaxVal>(vals...)==0,
"why doesn't this compile?");
}
};
MyClass<5, 1, 2, 3, 4> b;
template<int MaxVal> class MyClass
{
public:
template <int ... vals>
constexpr MyClass (std::integer_sequence<int, vals...> const &)
{
// verify at compile-time that all values in (vals) are <= MaxVal
static_assert(returnZeroIffValuesAreNotTooBig<MaxVal>(vals...)==0,
"why doesn't this compile?");
}
};
MyClass<5> b(std::integer_sequence<int, 1, 2, 3, 4>{});