c++ - Clang 3.7.0 提示类不是文字,因为它不是聚合并且没有 constexpr 构造函数

标签 c++ c++11 c++14 constexpr clang++

以下代码在 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 上运行的代码:

GCC & VC

Clang

您能否澄清这是编译器错误还是我遗漏了什么? 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>不能在常量表达式中调用。

但是,作为该规则的一个异常(exception),如果没有任何可能的模板参数可以导致实例化满足 constexpr 的通常要求|功能,程序格式错误,不需要诊断。这意味着编译器可以完全忽略此规则,但同样可以将代码诊断为 fatal error 。

一般来说,不可能可靠地检测到违反此规则的情况,这就是不需要诊断的原因。一些编译器比其他编译器更努力地提供一些诊断。

所有这些都在 [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.

关于c++ - Clang 3.7.0 提示类不是文字,因为它不是聚合并且没有 constexpr 构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40548269/

相关文章:

C++ for 循环跳过 cin.get()

c++ - OpenCV HOGDescriptor 堆崩溃

c++ - 可变参数模板 模板

c++ - 存在用户定义的析构函数时如何禁用隐式定义的复制构造函数生成

c++ - g++ 是否错误地抛出 -Wnarrowing?

c++ - 如何从可变参数模板参数创建 std::tuple<>?

c++ - Makefile C++11 - 编译成静态库

c++ - C++ 中的宽松内存排序

c++ - 获取第 n 个可变参数值(不是类型)

c++ - 如何填充unique_ptr数组?