【发布时间】:2016-01-13 19:30:50
【问题描述】:
我有以下代码可以在 g++ 下编译,但不能使用 clang。
如果以各种细微的方式更改代码,例如合并 2 个命名空间声明,Clang 将编译代码。
// The problem disappears without namespaces.
namespace Root {
// The problem disappears if 'g' is in the global namespace, and we change
// the friend declaration to '::g'
// The problem disappears if 'g' has void return type.
// The problem disappears if we get rid of the 'Value' template argument
// and the 'value' parameter.
template<typename Value, typename Defaulted = void>
bool g(Value value);
// The problem disappears if MyClass is not a template.
template<typename ClassValue>
class MyClass {
private:
template<typename Value, typename Defaulted>
friend bool g(Value value);
};
}
// The problem disappears if we declare the Root namespace in a single block
// containing 'g', 'MyClass' and 'f'.
// The problem remains if we declare f in the global namespace and reference
// Root::g.
namespace Root {
void f() {
MyClass<int> value;
g(value);
}
}
使用 clang 编译:
clang -fsyntax-only -std=c++11 testcase.cpp
使用 g++ 编译:
g++ -fsyntax-only -std=c++11 testcase.cpp
版本是 g++ 4.9.2、clang 3.6.0,都在 Ubuntu 核心 15.04 上。
Clang 给出错误信息:
testcase.cpp:24:9: error: no matching function for call to 'g'
g(value);
^
testcase.cpp:14:21: note: candidate template ignored: couldn't infer template argument 'Defaulted'
friend bool g(Value value);
^
1 error generated.
【问题讨论】:
-
友元函数(即使在类中声明)具有命名空间范围。所以在这种情况下,你有 2 个
bool Root::g()的函数声明。模板参数不会更改声明。这就是为什么您的微小更改使此代码起作用的原因。实际上我更惊讶的是它可以用 g++ 编译。 -
@SimonKraemer 您可以多次声明函数。并且
friend声明无论如何都不会重新声明该函数。 -
这是您的完整代码还是只是相关部分?
-
@Barry 你是对的。我的错。我试图用 MSVC 编译它并进入链接器错误。所以我定义了两个 g() 函数..... -.-
-
@SimonKraemer,这是原始问题的大幅缩减版本。最初是断言库与 int 库交互的问题(为了停止不安全的转换 - 我做了很多小事)。
标签: c++ c++11 clang language-lawyer