gpt4 book ai didi

c++ - 如果不使用模板类中的定义,是否应该实例化?

转载 作者:行者123 更新时间:2023-12-01 08:54:35 25 4
gpt4 key购买 nike

template <typename T>
struct A
{
static constexpr T obj {};

static constexpr bool noexcept_copy = noexcept( T{obj} );
static void UsesCopy() { T{obj}; }

static constexpr int C = 1;
};

struct NoCopy
{
constexpr NoCopy() = default;
NoCopy(const NoCopy&) = delete;
};

int main()
{
return A<NoCopy>::C;
}

上面的代码已由GCC成功编译,但是Clang给出了编译错误:
tmp.cpp:6:57: error: call to deleted constructor of 'NoCopy'
static constexpr bool noexcept_copy = noexcept( T{obj} );
^~~~~~
tmp.cpp:20:16: note: in instantiation of template class 'A<NoCopy>' requested here
return A<NoCopy>::C;
^
tmp.cpp:15:9: note: 'NoCopy' has been explicitly marked deleted here
NoCopy(const NoCopy&) = delete;
^
1 error generated.
A::UsesCopy函数也使用复制构造函数,但是编译器不会在此提示已删除函数的用法。 UsesCopy函数和 noexcept_copy constexpr有什么区别?两者都使用 NoCopy类的副本构造函数,并且都不使用,但是constexpr定义会产生编译错误,而函数定义则不会。

PS。 Clang使用 -std=c++17-std=c++2a编译上面的代码,但不使用 -std=c++11-std=c++14编译上面的代码。

最佳答案

我认为处理此问题的正确方法类似于this pre-C++17 answer to a question about the order of initialization of static constexpr templated data members中的详细信息。

TL; DR -是的,GCC,正确无误,Clang尝试解析副本c'tor,即使不允许这样做。

总结一下:

C++ 14

在p9.4.2.3-静态数据成员中,我们有:

[...] A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [...] The member shall still be defined in a namespace scope if it is odr-used in the program and the namespace scope definition shall not contain an initializer.



因此, static constexpr数据成员的声明只是一个声明,而不是一个定义-即使它具有初始化程序。需要进行定义才能进行初始化,并且原始OP代码中未提供任何定义。

为了说明这一点,我们前面引用了p14.7.1-模板-隐式实例化(强调我的意思):

The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, but not of the definitions, default arguments, or exception-specifications of the class member functions, member classes, scoped member enumerations, static data members and member template



GCC不会正确地初始化 noexcept_copy,因为它没有定义,只有一个declecle -从未按照p9.4.2.3的要求在“ namespace 范围内定义”。

C++ 17

那么,什么改变了?好吧,据我所知-没什么大不了的,但是在C++ 17中,通过采用 P0389R2定义了静态数据成员的方式有了一些变化,据我了解,它的目的是引入“内联变量”可以简单地声明它,然后在具有相同存储的多个转换单元中使用它,即声明中只有一个由初始化程序初始化的变量实例-这类似于其他语言(如Java)中的“静态字段初始化”并使其更容易进行单例初始化。

来自规格:

A declaration is a definition unless [...] it declares a non­-inline static data member in a class definition.



因此,我们明确指定 inline静态数据成员的声明 一个定义。不需要超出类范围的外部定义。这无疑使程序员更容易。

但是 inlineconstexpr有什么关系?该建议的采纳也导致在p10.1.5.1中产生此规范:

A function or static data member declared with the constexpr specifier is implicitly an inline function or variable.



因此,此更改实际上非常明确地表明 static constexpr bool noexcept_copy的声明也是一个定义-在隐式模板实例化的情况下我们不应实例化。

我猜想这对于Clang开发人员来说是足够强大的信号,可以不初始化 static constexpr数据成员。

顺便说一句,C++ 17附录D第1页中的示例相当明确地解释了这一点:

struct A {
static constexpr int n = 5; // definition (declaration in C++ 2014)
};
constexpr int A::n; // redundant declaration (definition in C++ 2014)

从此示例中我们了解到,在C++ 2014中, static constexpr的声明不是定义,并且为了进行初始化,您必须在 namespace 范围内具有定义。

因此Clang在其C++ 14实现中输出错误是错误的,因为在OP代码中,隐式实例化模板类静态数据成员不仅是错误的-甚至没有定义,因此它不应该具有被实例化,即使它不是模板类也是如此。

关于c++ - 如果不使用模板类中的定义,是否应该实例化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57609553/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com