为什么通过 const 引用传递 constexpr 对象有效,但按值不编译
Why passing constexpr object by const reference works, but by value doesn't compile
我有下面的代码,它基本上在编译时将 std::integer_sequence<>
映射到 std::array<>
:
#include <iostream>
#include <utility>
#include <array>
template<int...Is>
constexpr auto make_array(const std::integer_sequence<int, Is...>& param) // this works */
// constexpr auto make_array(std::integer_sequence<int, Is...> param) // doesn't compile
{
return std::array<int, sizeof...(Is)> {Is...};
}
int main()
{
constexpr std::integer_sequence<int, 1,2,3,4> iseq;
// If I pass by value, error: the value of 'iseq' is not usable in a constant expression
constexpr auto arr = make_array(iseq);
for(auto elem: arr)
std::cout << elem << " ";
}
只要 make_array
通过 const
-reference 获取其参数,代码就可以正常工作。每当我尝试按值传递它时,就像在注释行中一样,它会吐出一个错误:
error: the value of 'iseq' is not usable in a constant expression
constexpr auto arr = make_array(iseq);
这是为什么?参数iseq
肯定是常量表达式,为什么不能传给make_array
?
例如,下面的代码在按值传递时按预期工作:
#include <iostream>
#include <utility>
struct Foo
{
int _m;
constexpr Foo(int m): _m(m){};
};
constexpr Foo factory_foo(int m)
{
return Foo{m};
}
constexpr Foo copy_foo(Foo foo)
{
return foo;
}
int main()
{
constexpr Foo cxfoo = factory_foo(42);
constexpr Foo cpfoo = copy_foo(cxfoo);
}
编辑
我正在使用 macports 的 g++5.1。使用 clang++ 3.5,即使对于使用 g++ 编译的代码(使用 const
参考),我也会收到一条错误消息:
error: default initialization of an object of const type 'const
std::integer_sequence' requires a user-provided default
constructor
所以我猜想缺少用户提供的默认构造函数存在一些问题,但在这一点上我真的不明白发生了什么。
If a program calls for the default initialization of an object of a
const-qualified type T
, T
shall be a class type with a user-provided
default constructor.
但是,integer_sequence
没有任何用户提供的构造函数,并且 constexpr
隐含了 const
变量,所以你不能定义一个 constexpr
的对象没有初始值设定项的类型。
添加初始化程序 makes it compile on Clang.
您缺少 iseq
上的初始值设定项。你必须添加它:
constexpr std::integer_sequence<int, 1,2,3,4> iseq{};
^^
来自[dcl.constexpr]:
A constexpr
specifier used in an object declaration declares the object as const
. Such an object shall have
literal type and shall be initialized. If it is initialized by a constructor call, that call shall be a constant expression (5.20). Otherwise, or if a constexpr
specifier is used in a reference declaration, every fullexpression
that appears in its initializer shall be a constant expression. [ Note: Each implicit conversion
used in converting the initializer expressions and each constructor call used for the initialization is part of
such a full-expression. —end note ]
[ Example:
struct pixel {
int x, y;
};
constexpr pixel ur = { 1294, 1024 }; // OK
constexpr pixel origin; // error: initializer missing
—end example ]
此外,正如 Columbo 在他的 and 中建议的那样,仅仅进行初始化是不够的。根据 [dcl.init]:
,还需要用户提供的构造函数
If a program calls for the default initialization of an object of a const-qualified type T
, T
shall be a class type
with a user-provided default constructor.
最相关的部分 (dcl.constexpr) 对 constepxr
对象声明的要求的描述不完整,这有点奇怪。
我有下面的代码,它基本上在编译时将 std::integer_sequence<>
映射到 std::array<>
:
#include <iostream>
#include <utility>
#include <array>
template<int...Is>
constexpr auto make_array(const std::integer_sequence<int, Is...>& param) // this works */
// constexpr auto make_array(std::integer_sequence<int, Is...> param) // doesn't compile
{
return std::array<int, sizeof...(Is)> {Is...};
}
int main()
{
constexpr std::integer_sequence<int, 1,2,3,4> iseq;
// If I pass by value, error: the value of 'iseq' is not usable in a constant expression
constexpr auto arr = make_array(iseq);
for(auto elem: arr)
std::cout << elem << " ";
}
只要 make_array
通过 const
-reference 获取其参数,代码就可以正常工作。每当我尝试按值传递它时,就像在注释行中一样,它会吐出一个错误:
error: the value of 'iseq' is not usable in a constant expression
constexpr auto arr = make_array(iseq);
这是为什么?参数iseq
肯定是常量表达式,为什么不能传给make_array
?
例如,下面的代码在按值传递时按预期工作:
#include <iostream>
#include <utility>
struct Foo
{
int _m;
constexpr Foo(int m): _m(m){};
};
constexpr Foo factory_foo(int m)
{
return Foo{m};
}
constexpr Foo copy_foo(Foo foo)
{
return foo;
}
int main()
{
constexpr Foo cxfoo = factory_foo(42);
constexpr Foo cpfoo = copy_foo(cxfoo);
}
编辑
我正在使用 macports 的 g++5.1。使用 clang++ 3.5,即使对于使用 g++ 编译的代码(使用 const
参考),我也会收到一条错误消息:
error: default initialization of an object of const type 'const std::integer_sequence' requires a user-provided default constructor
所以我猜想缺少用户提供的默认构造函数存在一些问题,但在这一点上我真的不明白发生了什么。
If a program calls for the default initialization of an object of a const-qualified type
T
,T
shall be a class type with a user-provided default constructor.
但是,integer_sequence
没有任何用户提供的构造函数,并且 constexpr
隐含了 const
变量,所以你不能定义一个 constexpr
的对象没有初始值设定项的类型。
添加初始化程序 makes it compile on Clang.
您缺少 iseq
上的初始值设定项。你必须添加它:
constexpr std::integer_sequence<int, 1,2,3,4> iseq{};
^^
来自[dcl.constexpr]:
A
constexpr
specifier used in an object declaration declares the object asconst
. Such an object shall have literal type and shall be initialized. If it is initialized by a constructor call, that call shall be a constant expression (5.20). Otherwise, or if aconstexpr
specifier is used in a reference declaration, every fullexpression that appears in its initializer shall be a constant expression. [ Note: Each implicit conversion used in converting the initializer expressions and each constructor call used for the initialization is part of such a full-expression. —end note ]
[ Example:struct pixel { int x, y; }; constexpr pixel ur = { 1294, 1024 }; // OK constexpr pixel origin; // error: initializer missing
—end example ]
此外,正如 Columbo 在他的
If a program calls for the default initialization of an object of a const-qualified type
T
,T
shall be a class type with a user-provided default constructor.
最相关的部分 (dcl.constexpr) 对 constepxr
对象声明的要求的描述不完整,这有点奇怪。