【发布时间】:2018-07-12 13:32:50
【问题描述】:
所以在前面,我想要做的并不是课堂上朋友定义的真正预期用例。但它确实可以在 g++ 下工作,而且据我所知,它应该可以根据 C++14 规范工作。
出于讨论的目的,clang 是 5.0.0,gcc 是 7.2.0,尽管我已经使用其他最新版本和 HEAD 版本进行了测试并得到了相同的结果。使用 c++14 标志编译的所有内容。
我感兴趣的案例的最小复制如下。
#include <iostream>
auto foo();
template <typename T>
class Foo
{
friend auto foo()
{
return (T)3.14;
}
};
template <typename T>
void bar(T){}
int main()
{
bar(Foo<float>{});
std::cout << foo() << std::endl;
return 0;
}
Gcc 行为:编译并运行。输出:3.14
Clang 行为:拒绝编译。错误:“foo”的类型冲突
这本身似乎是完全错误的,但是由于当我删除 Foo 的模板化时 auto 不会给 clang 带来任何问题,所以我决定尝试给 foo 函数一个虚拟模板。
#include <iostream>
template <typename X = int>
auto foo();
template <typename T>
class Foo
{
template <typename X>
friend auto foo()
{
return (T)3.14;
}
};
template <typename T>
void bar(T){}
int main()
{
bar(Foo<float>{});
std::cout << foo() << std::endl;
return 0;
}
Gcc 行为:编译并运行。输出:3.14
Clang 行为:编译并运行。输出:3
是的,当使用 clang 编译时,foo 的类型推导完全取决于声明中的默认模板参数,尽管没有出现在定义中的任何地方。 o_O
最后,我决定尝试通过引入 using 指令来修复这种特殊行为。
#include <iostream>
template <typename X = int>
auto foo();
template <typename T>
class Foo
{
using Type = T;
template <typename X>
friend auto foo()
{
return (Type)3.14;
}
};
template <typename T>
void bar(T){}
int main()
{
bar(Foo<float>{});
std::cout << foo() << std::endl;
return 0;
}
Gcc 行为:编译并运行。输出:3.14
Clang 行为:编译器崩溃。我尝试过的每个版本。
崩溃是一个明显的错误,但我对前两个示例更感兴趣。这也是clang中的错误吗?或者是否有一些微妙的原因可以解释为什么这应该是未定义的行为,而我只是对 gcc 感到幸运?更重要的是,谁能想到一种适用于 gcc 和 clang 的解决方法?我正在尝试做的事情是检测 Foo 实例化的类型,前提是它是唯一的,在编译时从 Foo 外部。
【问题讨论】:
标签: templates g++ c++14 friend clang++