gpt4 book ai didi

c++ - C++模板函数中,依赖函数调用为什么报 "not declared"错误?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:58:41 24 4
gpt4 key购买 nike

在 C++ 模板函数 foo() 中,调用::bar(TT*) 在 gcc 4.4.3 下会出现以下错误:

g++ -o hello.o -c -g hello.cpp
hello.cpp: In function 'void foo(std::vector<TT*, std::allocator<TT*> >&)':
hello.cpp:8: error: '::bar' has not been declared

这是有问题的代码:

// hello.cpp

#include <vector>

template<typename TT> void foo(std::vector<TT*> &vec)
{
TT *tt;
::bar(tt);
vec.push_back(tt);
}

class Blah
{
};

void bar(Blah *&)
{
}

int main(int argc, char *argv[])
{
std::vector<Blah*> vec;
foo(vec);

return 0;
}

C++ 区分依赖于模板参数(此处为 TT)的符号和那些独立且可以立即求值的符号。

显然,编译器认为我的::bar(TT*) 调用是独立的,并试图立即解决它。同样清楚的是,该函数调用依赖于 TT,因为该函数调用采用 TT* 类型的参数,因此编译器应等到 foo(vec) 实例化以解析::bar(TT* ).

这是一个 gcc 错误还是我遗漏了有关 C++ 模板的一些细微之处?

编辑:这里有一个稍微复杂一些的例子,有两个版本的::bar() 来澄清声明顺序不是我的问题的问题。解析模板时,编译器没有知道下面的 main() 是使用 TT=Blah 还是 TT=Argh 来实例化模板函数。因此,编译器最早不应该在 line 35 line 28 之前(如果有的话)给出错误。但是错误出现在 line 8 line 16.

编辑#2:改进了这个例子。

编辑#3:对这个例子进行了更正,使其按预期工作。 bar(tt) 现在可以正确引用 bar(Blah*)。理由如下。 (谢谢大家)。

// hello.cpp
#include <vector>

class XX {};
void bar(XX*) {}

class CC {
public:
void bar();
void bar(int *);
void bar(float *);

template<typename TT> static void foo(std::vector<TT*> &vec);
};

template<typename TT>
void CC::foo(std::vector<TT*> &vec) {
using ::bar;
TT *tt;
bar(tt);
vec.push_back(tt);
}

class Argh {};
void bar(Argh *&aa) { aa = new Argh; }

class Blah {};
void bar(Blah *&bb) { bb = new Blah; }

int main(int argc, char *argv[]) {
std::vector<Blah*> vec;
CC::foo(vec);
return 0;
}

最佳答案

Nobody has yet pointed out any part of the current Standard that says I can't.

C++03 不依赖名称 ::bar。依赖类型发生在类型名称上,非类型名称发生在依赖类型或值的依赖表达式上。如果在依赖类型中查找名称,它将成为类型依赖的 id 表达式(14.6.2.2/3 最后一个项目符号),并且它的查找被延迟到实例化。名称 ::bar 不是这样的依赖表达式。如果你要调用 bar(tt),C++03 在 14.2.6 的特殊规则说

In an expression of the form:

postfix-expression ( expression-listopt )

where the postfix-expression is an identifier, the identifier denotes a dependent name if and only if any of the expressions in the expression-list is a type-dependent expression (14.6.2.2).

因此您需要删除 :: 以使其成为标识符并使​​其依赖于此特殊规则。

The reason I can't remove the :: is that in my real code, the template function foo is a member function of class CC, and there exist a family of overloaded member functions CC::bar(...), meaning I need to qualify ::bar(TT*) to avoid defaulting to CC::bar(...). That's what :: exists for, I'm surprised if the Standard says I can't use :: here

解决它的正确方法是在函数的局部范围内引入一个 using 声明。

namespace dummies { void f(); }
template<typename T>
struct S {
void f();
void g() {
using dummies::f; // without it, it won't work
f(T()); // with ::f, it won't work
}
};

struct A { };
void f(A) { } // <- will find this

int main() {
S<A> a;
a.g();
}

如果普通查找找到类成员函数,ADL 将不会执行任何操作。因此,你引入一个using声明,所以普通查找找不到类成员函数,ADL可以在实例化时推进可见的声明。

But this seems to disagree with you: Stroustrup TC++PL Sp Ed, Section C.13.8.1, Dependent Names: "Basically, the name of a function called is dependent if it is obviously dependent by looking at its arguments or at its formal parameters"

Stroustrup 的书也是为可能还不了解 C++ 的人编写的。它不会尝试以 100% 的准确性涵盖所有规则,这对这些书来说是正常的。血淋淋的细节留给 ISO 标准读者。

另外,函数的形参与函数调用是否依赖无关。在 IS 中,只有实际参数定义函数名称的依赖性。这在 an old draft from 1996 中有所不同。 ,它具有隐式显式 依赖的概念。隐式依赖定义为

A name implicitly depends on a template-argument if it is a function name used in a function call and the function call would have a dif- ferent resolution or no resolution if a type, template, or enumerator mentioned in the template-argument were missing from the program.

[...]

[Example: some calls that depend on a template-argument type T are:

  1. The function called has a parameter that depends on T according to the type deduction rules (temp.deduct). For example, f(T), f(Array), and f(const T*).

  2. The type of the actual argument depends on T. For example, f(T(1)), f(t), f(g(t)), and f(&t) assuming that t has the type T.

还给出了实际例子

This ill-formed template instantiation uses a function that does not depend on a template-argument:

template<class T> class Z {
public:
void f() const
{
g(1); // g() not found in Z's context.
// Look again at point of instantiation
}
};

void g(int);
void h(const Z<Horse>& x)
{
x.f(); // error: g(int) called by g(1) does not depend
// on template-argument ``Horse''
}

The call x.f() gives rise to the specialization:

void Z<Horse>::f() { g(1); }

The call g(1) would call g(int), but since that call does not depend on the template-argument Horse and because g(int) was not in scope at the point of the definition of the template, the call x.f() is ill- formed.

On the other hand:

void h(const Z<int>& y)
{
y.f(); // fine: g(int) called by g(1) depends
// on template-argument ``int''
}

Here, the call y.f() gives rise to the specialization:

void Z<int>::f() { g(1); }

The call g(1) calls g(int), and since that call depends on the tem- plate-argument int, the call y.f() is acceptable even though g(int) wasn't in scope at the point of the template definition. ]

这些东西留给了历史,甚至它的最后痕迹也在慢慢消失,尽管不是主动驱动的(例如,n3126 摆脱了 [temp.names]/p4 的“明确依赖”,作为另一个变化,因为“显式依赖”和“隐式依赖”之间的区别在 IS 中从未存在过)。

关于c++ - C++模板函数中,依赖函数调用为什么报 "not declared"错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3951209/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com