我一直在尝试使用 Sean Parent 的“C++ Seasoning”演示文稿派生的代码,并将我的问题归结为以下代码:
#include <memory>
struct container {
struct concept {
virtual ~concept() {}
virtual void foo_() = 0;
};
template <class T> struct model : concept {
model (T x) : data_(x) {}
void foo_() {
foo(data_); // Line 13
}
T data_;
};
template <class T>
container(T x) : self_(new model<T>(x)) {} // Line 20
std::unique_ptr<concept> self_;
friend void foo(container &c) { c.self_->foo_(); }
};
void foo(int i) // Line 27
{
}
int main()
{
int i = 5;
container c(i); // Line 34
foo(c);
}
我遇到的问题是这段代码是用 g++ 编译的,但不是用 Clang 编译的。
Clang 给我以下错误信息:
prio.cpp:13:13: error: call to function 'foo' that is neither visible in the
template definition nor found by argument-dependent lookup
foo(data_);
^
prio.cpp:20:32: note: in instantiation of member function
'container::model<int>::foo_' requested here
container(T x) : self_(new model<T>(x)) {}
^
prio.cpp:34:15: note: in instantiation of function template specialization
'container::container<int>' requested here
container c(i);
^
prio.cpp:27:6: note: 'foo' should be declared prior to the call site
void foo(int i)
^
我的理解是,模板期间的重载决策发生在实例化时。在本例中,即第 34 行(如上标记)。此时,全局“foo”函数是已知的。然而,它似乎没有解决。
后代注意事项:这是 Clang 在 14/Jan/14 从主干构建的
那么这是 Clang 中的错误,还是 g++ 中的错误?
最佳答案
在这种情况下 Gcc 是错误的,代码应该不编译;但这与模板完全无关。友元声明的特殊之处在于它们为 namespace 级实体提供了声明,但是在编译器也看到 namespace 声明之前,该声明对于正常查找是可见的。
考虑简化的例子:
struct X {
friend void f(int); // [1]
void g() { f(1); } // [2]
};
void h() { f(1); } // [3]
void f(int); // [4]
void i() { f(1); } // [5]
X
类中的 friend 声明 [1] 为命名空间级函数 f
提供了声明,该函数采用 int
,但是 在 [4] 中出现命名空间级声明之前,该声明在命名空间级不可见。 [2] 和 [3] 都将无法编译,尽管 [5] 会编译,因为此时编译器已经解析了函数声明。
那么编译器如何使用[1]中的声明来解析调用呢?在这种特殊情况下从不。友元声明只能通过参数相关查找找到,但如果函数调用的参数之一是 X
类型,ADL 只会在 X
内部查找。在这种情况下,该函数没有任何参数 X
,因此查找将从不使用 friend
声明来解除限制访问 X
的变量。
即:
struct Y {
friend void f(int) {}
};
如果 f
没有后面的 namespace 级别声明,将声明和定义一个不能在程序中的任何地方使用的函数(查找永远找不到它)。
您的问题的简单解决方法是在定义类之前在命名空间级别为函数提供声明:
#include <memory>
void foo(int);
struct container { // ...
关于c++ - Clang 在模板上下文中找不到函数定义后实例化的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21115247/