关于使用 Singleton CRTP 的模板参数类型的内联静态成员,哪个编译器是正确的?
Which compiler is right about inline static members of template parameter type using a Singleton CRTP?
我制作了一个非常简单的 Singleton
基础 class,它可以与 CRTP 一起使用,使任何从它派生的 class 成为单例。不过我发现了一些奇怪的事情。不同的编译器不同意代码是否格式错误。在这里:
template <typename Derived>
class Singleton
{
public:
inline static Derived instance;
};
正如我所说,它非常简单,但足以用于演示目的。此处显示了一个示例用法:
class MyClass : public Singleton<MyClass>
{
public:
std::string msg;
MyClass() = default;
MyClass(const std::string& msg_) : msg{ msg_ }
{
}
MyClass(std::string&& msg_) noexcept : msg{ std::move(msg_) }
{
}
};
这段代码在 GCC, and Clang. However MSVC 下编译通过说 MyClass
没有提供适当的默认构造函数来拒绝它(尽管它显然被声明为 default
)。出于好奇,我尝试使用不同的构造函数:
template <typename Derived>
class Singleton
{
public:
inline static Derived instance{"hello MSVC"};
};
class MyClass : public Singleton<MyClass>
{
public:
std::string msg;
MyClass() = default;
MyClass(const std::string& msg_) : msg{ msg_ }
{
}
MyClass(std::string&& msg_) noexcept : msg{ std::move(msg_) }
{
}
};
这再次被 GCC and Clang, but rejected by MSVC 接受,它声称这次 MyClass
未定义。
问题是:这段代码格式不正确吗?如果是,为什么? 因此,哪些编译器是正确的? GCC 和 Clang 只是利用“不需要诊断”的优势吗?
我的直觉是 MSVC 是错误的,因为通常是这种情况,尽管另一方面,它通常比 GCC 和 Clang 更宽松,所以我很好奇答案。
GCC 和 Clang 是正确的。
The implicit instantiation of a class template specialization causes
- the implicit instantiation of the declarations, but not of the definitions, of the non-deleted class member functions, member classes, scoped member enumerations, static data members, member templates, and friends; and
- the implicit instantiation of the definitions of deleted member functions, unscoped member enumerations, and member anonymous unions.
在 Singleton<Derived>
实例化的上下文中,Derived
确实是不完整的,但这并不重要,因为可以用不完整的类型声明。
另请参阅:gcc bug #71534
我制作了一个非常简单的 Singleton
基础 class,它可以与 CRTP 一起使用,使任何从它派生的 class 成为单例。不过我发现了一些奇怪的事情。不同的编译器不同意代码是否格式错误。在这里:
template <typename Derived>
class Singleton
{
public:
inline static Derived instance;
};
正如我所说,它非常简单,但足以用于演示目的。此处显示了一个示例用法:
class MyClass : public Singleton<MyClass>
{
public:
std::string msg;
MyClass() = default;
MyClass(const std::string& msg_) : msg{ msg_ }
{
}
MyClass(std::string&& msg_) noexcept : msg{ std::move(msg_) }
{
}
};
这段代码在 GCC, and Clang. However MSVC 下编译通过说 MyClass
没有提供适当的默认构造函数来拒绝它(尽管它显然被声明为 default
)。出于好奇,我尝试使用不同的构造函数:
template <typename Derived>
class Singleton
{
public:
inline static Derived instance{"hello MSVC"};
};
class MyClass : public Singleton<MyClass>
{
public:
std::string msg;
MyClass() = default;
MyClass(const std::string& msg_) : msg{ msg_ }
{
}
MyClass(std::string&& msg_) noexcept : msg{ std::move(msg_) }
{
}
};
这再次被 GCC and Clang, but rejected by MSVC 接受,它声称这次 MyClass
未定义。
问题是:这段代码格式不正确吗?如果是,为什么? 因此,哪些编译器是正确的? GCC 和 Clang 只是利用“不需要诊断”的优势吗?
我的直觉是 MSVC 是错误的,因为通常是这种情况,尽管另一方面,它通常比 GCC 和 Clang 更宽松,所以我很好奇答案。
GCC 和 Clang 是正确的。
The implicit instantiation of a class template specialization causes
- the implicit instantiation of the declarations, but not of the definitions, of the non-deleted class member functions, member classes, scoped member enumerations, static data members, member templates, and friends; and
- the implicit instantiation of the definitions of deleted member functions, unscoped member enumerations, and member anonymous unions.
在 Singleton<Derived>
实例化的上下文中,Derived
确实是不完整的,但这并不重要,因为可以用不完整的类型声明。
另请参阅:gcc bug #71534