[英]Why does C++'s `variable template` not behave as expected?
#include <type_traits>
template<typename T>
struct remove_cvref
{
using type = std::remove_cv_t<
std::remove_reference_t<T>>;
};
template<typename T>
using remove_cvref_t =
typename remove_cvref<T>::type;
template<typename T>
constexpr bool isCc = std::is_copy_constructible_v<
remove_cvref_t<T>>;
class A final
{
public:
A() = default;
template<typename T, bool = isCc<T>> // error
A(T&&) {}
};
A f()
{
A a;
return a;
}
int main()
{}
The error message: 错误消息:
error : constexpr variable 'isCc<const A &>' must be initialized by a constant expression
1>main.cpp(14): note: in instantiation of variable template specialization 'isCc<const A &>' requested here
1>main.cpp(15): note: in instantiation of default argument for 'A<const A &>' required here
1>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include\type_traits(847): note: while substituting deduced template arguments into function template 'A' [with T = const A &, b1 = (no value)]
1>main.cpp(8): note: in instantiation of variable template specialization 'std::is_copy_constructible_v<A>' requested here
1>main.cpp(14): note: in instantiation of variable template specialization 'isCc<A>' requested here
1>main.cpp(15): note: in instantiation of default argument for 'A<A>' required here
1>main.cpp(21): note: while substituting deduced template arguments into function template 'A' [with T = A, b1 = (no value)]
However, if I change the class A
as follows: 但是,如果我按如下方式更改
A
类:
class A final
{
public:
A() = default;
template<typename T,
bool = std::is_copy_constructible_v<
remove_cvref_t<T>>> // ok
A(T&&) {}
};
Then everything is ok. 一切都好。
Why does C++'s variable template
not behave as expected? 为什么C ++的
variable template
表现不如预期?
At the point where std::is_copy_constructible_v<A>
is being instantiated, ie immediately after the definition of isCc
, A
is not complete, while std::is_copy_constructible_v
requires its template argument to be complete. 在实例化
std::is_copy_constructible_v<A>
,即在isCc
定义isCc
, A
未完成,而std::is_copy_constructible_v
要求其模板参数完成。
Whether this code should work is still a drafting issue: Core Language Issue 287 , so it is reasonable that some compilers accept your code while others reject it. 这段代码是否应该起作用仍然是一个起草问题: 核心语言问题287 ,所以一些编译器接受你的代码而其他编译器拒绝它是合理的。
In the version without isCc
, even at the point std::is_copy_constructible_v<A>
is being instantiated, A
is complete 1 , so all compilers happily accept the code. 在没有
isCc
的版本中,即使在实例化std::is_copy_constructible_v<A>
, A
也是完整的1 ,因此所有编译器都乐于接受代码。
1 Related rules in the standard: 1标准中的相关规则:
[class.member]/6 [class.member] / 6
A complete-class context of a class is a
一个完整的类的上下文是一个
- function body,
功能体,
- default argument,
默认参数,
- noexcept-specifier ([except.spec]),
noexcept-specifier([except.spec]),
- contract condition, or
合同条件,或
- default member initializer
默认成员初始化程序
within the member-specification of the class ...
在类的成员规范内......
[class.member]/7 [class.member] / 7
... The class is regarded as complete within its complete-class contexts ...
......在完整的课堂环境中,课程被认为是完整的......
I had successfully compiled the OP's
original proposed code in Visual Studio 2017 CE version 15.8.6 with my compiler's language standard set to ISO C++ Latest Draft Standard (/std:c++latest)
in my IDE's
settings and my machine is running Windows 7 64bit Ultimate. 我已经在我的
IDE's
设置中将我的编译器语言标准设置为ISO C++ Latest Draft Standard (/std:c++latest)
,并且我的机器运行的是Windows 7,在Visual Studio 2017 CE版本15.8.6中成功编译了OP's
原始建议代码64位终极版。 I built & rand the code in Debug - x86
mode. 我在
Debug - x86
模式下构建并修改了代码。
I even went as far and made a call to his function f()
within main, and it still built, compiled, ran and exited without error. 我甚至走了很远,并在main中调用了他的函数
f()
,它仍然构建,编译,运行和退出而没有错误。
He then replied back in the comments with: 然后,他在评论中回复说:
My compiler is clang 7.0 on windows
我的编译器在Windows上是clang 7.0
I don't know if this is either a bug in Clang's
compiler or if Clang
just interprets it differently. 我不知道这是否是
Clang's
编译器中的错误,或者Clang
只是以不同的方式解释它。
Maybe try compiling your original attempt with different compilers if you are able to, try GCC
or a different version of Clang
and see if you get different results. 如果你能尝试用不同的编译器编译原始尝试,可以试试
GCC
或不同版本的Clang
,看看你是否得到不同的结果。
This is something interesting that I believe needs further investigation to determine if it has to do with Clang's
compiler specifically or not. 这是一个有趣的东西,我认为需要进一步调查,以确定它是否与
Clang's
编译器有关。
is_copy_constructible_v
has been added in C++17 while std::remove_cvref
is to be added in C++20. is_copy_constructible_v
已添加到C ++ 17中,而std::remove_cvref
将添加到C ++ 20中。 C++20 support is still experimental. C ++ 20支持仍然是实验性的。
Writing proper C++14 code will solve the problem: 编写适当的C ++ 14代码将解决问题:
template<typename T>
constexpr bool isCc = std::is_copy_constructible<std::remove_reference_t<::std::remove_cv_t<T>>>::value;
or C++17: 或者C ++ 17:
template<typename T>
constexpr bool isCc = std::is_copy_constructible_v<std::remove_reference_t<::std::remove_cv_t<T>>>;
Answer to next question: 回答下一个问题:
std::is_copy_constructible
template parameter requirements are std::is_copy_constructible
模板参数要求是
T shall be a complete type, cv void, or an array of unknown bound.
T应为完整类型,cv void或未知边界数组。
which is not in case of template<typename T, bool = isCc<T>>
when T is A
这不是
template<typename T, bool = isCc<T>>
当T是A
时template<typename T, bool = isCc<T>>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.