作为我前一个问题的一个有趣的后续(虽然不具有重大的实际意义): 为什么C++允许我们在声明变量时用括号括起变量名?
我发现将括号中的声明与注入的类名称功能相结合可能会导致有关编译器行为的惊人结果.
看看以下程序:
#include <iostream>
struct B
{
};
struct C
{
C (){ std::cout << "C" << '\n'; }
C (B *) { std::cout << "C (B *)" << '\n';}
};
B *y = nullptr;
int main()
{
C::C (y);
}
Run Code Online (Sandbox Code Playgroud)
用g ++ 4.9.2编译给出了以下编译错误:
main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive]
Run Code Online (Sandbox Code Playgroud)它与MSVC2013/2015成功编译并打印 C (B *)
它与clang 3.5成功编译并打印 C
因此,强制性问题是哪一个是正确的?:)
(我强烈倾向于clang版本和msvc方式停止声明变量后,只是在技术上改变类型,其typedef似乎有点奇怪)
今天我正在玩模板,看看我是否可以让编译器从其内部类中推断出外部类的类型.我没有找到我的解决方案(我怀疑是不可能的),但在尝试修复错误时,我遇到了非常奇怪的行为,我沦为下面的代码片段.
struct A
{
struct B{};
template <typename T>
struct EverythingIsFine
{
using Outer = T;
using Inner = typename T::B::B::B::B::B::B;
};
using ItWillBeOkay = EverythingIsFine<B>; // Probably not ok
using InnerProblem = ItWillBeOkay::Inner; // Still not ok
using OuterProblem = decltype(B().ItWillBeOkay::Outer::B::B::B
::B::B::B::~B()); // Not even CLOSE to ok
};
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是,Clang和GCC都没有警告,没有任何错误.
我的编译器的版本是gcc version 5.3.1 20160121 (Debian 5.3.1-7)和,Debian clang version 3.6.2-3 (tags/RELEASE_362/final) (based on LLVM 3.6.2)并且用于编译的标志是-std=c++11 -Wall -Wextra.
我发现它在使用C++ 14设置的Ideone上编译也很好.
然后我使用这个简单的测试来获得确切的类型InnerProblem和 …
这要从一次观察开始。我更改了一些看起来有点像这样的代码(编辑:我在这里取出了指定的初始值设定项,这些初始值设定项也不在原始代码中):
\n\nstruct S {\n enum E { E1, E2 } member;\n}\n\n// file1.cc\nS v1 = { S::E1 };\n\n// file2.cc\nS v2 = { S::S::E2 };\nRun Code Online (Sandbox Code Playgroud)\n\n请注意,file2.cc过度限定E2. 但这在 g++ 和 clang++ 中都有效。(编辑 2:这个特定 VM 上的 g++ 是 g++-5.4.1,但原始代码已经经历了早期和晚期的 g++ 版本,以及多个 clang 版本。)事实上,我们可以编写:
S v3 = { S::S::S::S::S::S::S::E1 };\nRun Code Online (Sandbox Code Playgroud)\n\n(无论S::我们喜欢多少),无论我们喜欢在哪里。我改变了一些东西,使它S不再是一个普通的struct,而是一个模板化的,之后就停止工作了。没什么大不了的,但这让我很好奇,所以我尝试了一下。
如果我们将其更改为非 POD 类型:
\n\nstruct S {\n S() { std::cout << "made an S" << std::endl; }\n enum E …Run Code Online (Sandbox Code Playgroud)