- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
在 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:
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*).
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/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!