问题
The following code compiles fine in GCC (4.9.3) and VC++ (19.00.23506) but gives these error in 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
Code:
#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;
}
Code running on rextester:
GCC & VC
Clang
Can you please clarify whether this is a compiler bug or have I missed something? What does the C++11 standard say?
Here is one other case where it compiles in GCC and VC but not in 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;
}
However, if you alias the int[] and explicitly use it to specify the type of the initializer_list, then it works in all compilers.
#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;
}
回答1:
All the compilers are right.
With function templates, in general, it's possible that one instantiation meets the requirements for a constexpr
function, but another doesn't. Normally, that means constexpr
effectively gets ignored silently for those instantiations that don't meet the requirements. Example:
template <typename T> constexpr T f(T v) { return v; }
Both the f<int>
and f<std::string>
instantiations are valid, but f<std::string>
cannot be called in a constant expression.
However, as an exception to that rule, if there isn't any possible template argument that could lead to an instantiation that meets the usual requirements for constexpr
functions, the program is ill-formed, no diagnostic required. This means compilers are at liberty to ignore this rule entirely, but they are equally allowed to diagnose the code as a fatal error.
In general, it's not possible to reliably detect violations of this rule, that's why no diagnostic is required. Some compilers try harder than others to still give some diagnostics.
All of this is described in the standard in [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.
来源:https://stackoverflow.com/questions/40548269/clang-3-7-0-complains-of-class-not-being-literal-because-it-is-not-an-aggregate