Clang 3.7.0 抱怨 class 不是文字,因为它不是聚合并且没有 constexpr 构造函数
Clang 3.7.0 complains of class not being literal because it is not an aggregate and has no constexpr constructors
以下代码在 GCC (4.9.3) 和 VC++ (19.00.23506) 中可以正常编译,但在 Clang (3.7.0) 中会出现这些错误。
error: constexpr function's return type 'Foo' is not a literal type
note: 'Foo' is not literal because it is not an aggregate and has no
constexpr constructors other than copy or move constructors
代码:
#include <iostream>
#include <vector>
struct Foo
{
std::vector<int> m_vec;
Foo(const int *foo, std::size_t size=0):m_vec(foo, foo+size)
{;}
//Foo(const std::initializer_list<int> &init):m_vec{init}
//{;}
};
template <std::size_t N>
constexpr Foo make_fooArray(const int (&a)[N]) noexcept
{
return {a,N};
}
int main()
{
Foo f{ make_fooArray({1,2,3}) };
for (auto i : f.m_vec)
std::cout<< i <<" ";
std::cout<<std::endl;
}
rextester 上的代码 运行:
能否请您澄清这是编译器错误还是我遗漏了什么? C++11 标准怎么说?
这是另一种情况,它可以在 GCC 和 VC 中编译,但不能在 Clang 中编译。
#include <iostream>
template <typename T, std::size_t N>
constexpr std::size_t sizeOf_fooArray(const T (&)[N]) noexcept
{
return N;
}
int main()
{
std::cout<< sizeOf_fooArray({16,20,53,87,54,7}) <<std::endl;
}
但是,如果您为 int[] 设置别名并明确使用它来指定 initializer_list 的类型,那么它适用于所有编译器。
#include <iostream>
template <typename T, std::size_t N>
constexpr std::size_t sizeOf_fooArray(const T (&)[N]) noexcept
{
return N;
}
using intArray = int[]; //Added
int main()
{
std::cout<< sizeOf_fooArray(intArray{16,20,53,87,54,7}) <<std::endl;
}
所有的编译器都是正确的。
对于函数模板,一般来说,有可能一个实例化满足 constexpr
函数的要求,而另一个不满足。通常,这意味着 constexpr
对于那些不符合要求的实例有效地被无声地忽略。示例:
template <typename T> constexpr T f(T v) { return v; }
f<int>
和f<std::string>
实例化都有效,但是f<std::string>
不能在常量表达式中调用。
但是,作为该规则的一个例外,如果没有 任何 可能的模板参数可以导致满足 constexpr
的通常要求的实例化功能,程序格式错误,不需要诊断。这意味着编译器可以完全忽略此规则,但同样可以将代码诊断为致命错误。
一般来说,不可能可靠地检测到违反此规则的情况,这就是不需要诊断的原因。一些编译器比其他编译器更努力地提供一些诊断。
所有这些都在 [dcl.constexpr]p6:
中的标准中进行了描述
If the instantiated template specialization of a constexpr
function template or member function of a class template would fail to satisfy the requirements for a constexpr
function or constexpr
constructor, that specialization is still a constexpr
function or constexpr
constructor, even though a call to such a function cannot appear in a constant expression. If no specialization of the template would satisfy the requirements for a constexpr
function or constexpr
constructor when considered as a non-template function or constructor, the template is ill-formed; no diagnostic required.
以下代码在 GCC (4.9.3) 和 VC++ (19.00.23506) 中可以正常编译,但在 Clang (3.7.0) 中会出现这些错误。
error: constexpr function's return type 'Foo' is not a literal type
note: 'Foo' is not literal because it is not an aggregate and has no constexpr constructors other than copy or move constructors
代码:
#include <iostream>
#include <vector>
struct Foo
{
std::vector<int> m_vec;
Foo(const int *foo, std::size_t size=0):m_vec(foo, foo+size)
{;}
//Foo(const std::initializer_list<int> &init):m_vec{init}
//{;}
};
template <std::size_t N>
constexpr Foo make_fooArray(const int (&a)[N]) noexcept
{
return {a,N};
}
int main()
{
Foo f{ make_fooArray({1,2,3}) };
for (auto i : f.m_vec)
std::cout<< i <<" ";
std::cout<<std::endl;
}
rextester 上的代码 运行:
能否请您澄清这是编译器错误还是我遗漏了什么? C++11 标准怎么说?
这是另一种情况,它可以在 GCC 和 VC 中编译,但不能在 Clang 中编译。
#include <iostream>
template <typename T, std::size_t N>
constexpr std::size_t sizeOf_fooArray(const T (&)[N]) noexcept
{
return N;
}
int main()
{
std::cout<< sizeOf_fooArray({16,20,53,87,54,7}) <<std::endl;
}
但是,如果您为 int[] 设置别名并明确使用它来指定 initializer_list 的类型,那么它适用于所有编译器。
#include <iostream>
template <typename T, std::size_t N>
constexpr std::size_t sizeOf_fooArray(const T (&)[N]) noexcept
{
return N;
}
using intArray = int[]; //Added
int main()
{
std::cout<< sizeOf_fooArray(intArray{16,20,53,87,54,7}) <<std::endl;
}
所有的编译器都是正确的。
对于函数模板,一般来说,有可能一个实例化满足 constexpr
函数的要求,而另一个不满足。通常,这意味着 constexpr
对于那些不符合要求的实例有效地被无声地忽略。示例:
template <typename T> constexpr T f(T v) { return v; }
f<int>
和f<std::string>
实例化都有效,但是f<std::string>
不能在常量表达式中调用。
但是,作为该规则的一个例外,如果没有 任何 可能的模板参数可以导致满足 constexpr
的通常要求的实例化功能,程序格式错误,不需要诊断。这意味着编译器可以完全忽略此规则,但同样可以将代码诊断为致命错误。
一般来说,不可能可靠地检测到违反此规则的情况,这就是不需要诊断的原因。一些编译器比其他编译器更努力地提供一些诊断。
所有这些都在 [dcl.constexpr]p6:
中的标准中进行了描述If the instantiated template specialization of a
constexpr
function template or member function of a class template would fail to satisfy the requirements for aconstexpr
function orconstexpr
constructor, that specialization is still aconstexpr
function orconstexpr
constructor, even though a call to such a function cannot appear in a constant expression. If no specialization of the template would satisfy the requirements for aconstexpr
function orconstexpr
constructor when considered as a non-template function or constructor, the template is ill-formed; no diagnostic required.