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>{});