当我发现以下可编译gcc
但不编译的代码时,我正在尝试在折叠表达式中使用任意函数clang
。
enum Enum {
A = 3,
B = 8,
C = 5
};
namespace EnumMax {
constexpr Enum operator>>=(const Enum left, const Enum right) {
return left < right ? right : left;
}
}
template<Enum ... enums>
constexpr Enum max() {
using EnumMax::operator>>=;
return (enums >>= ...);
}
constexpr Enum max_v = max<A, B, C>();
Run Code Online (Sandbox Code Playgroud)
似乎clang
不考虑重载运算符,而是尝试>>=
在fold表达式中使用正则运算符。
但是,如果改写了fold表达式,clang
则考虑重载运算符,并且可以正常编译:
constexpr Enum maxExplicit() {
using EnumMax::operator>>=;
return (A >>= (B …
Run Code Online (Sandbox Code Playgroud) 以下代码使用编译和链接Visual Studio
(2017和2019都使用/permissive-
),但不使用gcc
或进行编译clang
。
foo.h
Run Code Online (Sandbox Code Playgroud)#include <memory> struct Base { virtual ~Base() = default; // (1) }; struct Foo : public Base { Foo(); // (2) struct Bar; std::unique_ptr<Bar> bar_; };
foo.cpp
Run Code Online (Sandbox Code Playgroud)#include "foo.h" struct Foo::Bar {}; // (3) Foo::Foo() = default;
main.cpp
Run Code Online (Sandbox Code Playgroud)#include "foo.h" int main() { auto foo = std::make_unique<Foo>(); }
我的理解是,in main.cpp
中的Foo::Bar
必须是完整类型,因为in中尝试将其删除~Foo()
,它是隐式声明的,因此在访问它的每个翻译单元中都是隐式定义的。
但是,Visual Studio
不同意,并接受此代码。此外,我发现以下更改使Visual Studio
代码遭到拒绝:
(1)
非虚拟(2)
内联-即Foo() …
c++ visual-c++ language-lawyer delete-operator incomplete-type
在思考这个问题时,我偶然发现了我不了解的其他内容。
标准说...
如果类没有用户声明的析构函数,则将析构函数隐式声明为默认值。隐式声明的析构函数是其类的内联公共成员。
[...]如果类具有带有虚拟析构函数的基类,则其析构函数(无论是用户声明的还是隐式声明的)都是虚拟的。
默认使用但未定义为deleted的析构函数在使用odr时或在其首次声明后被明确默认为隐式定义。
[...]如果虚拟成员函数不是纯函数,则将被使用。[...]
所以现在我想知道这段代码是否应该编译:
#include <memory>
struct Base {
virtual ~Base() = default;
};
struct Bar;
struct Foo : Base {
std::unique_ptr<Bar> bar_{};
};
Run Code Online (Sandbox Code Playgroud)
我认为~Foo()
必须对其进行隐式定义,因为它是虚拟的,但由于Bar
在此TU中不完整,因此无法编译。但是代码可以在所有主要的编译器中编译。
我想念什么?
c++ one-definition-rule language-lawyer implicit-declaration virtual-destructor