gpt4 book ai didi

c++ - 模板内的参数相关查找

转载 作者:太空狗 更新时间:2023-10-29 21:46:02 26 4
gpt4 key购买 nike

我对模板上下文中的函数名称查找感到困惑。我知道编译器会延迟模板化代码中依赖于参数的标识符查找,直到模板被实例化。这意味着您有时会在模板化代码中出现语法错误或调用不存在的函数,除非您实际实例化模板,否则编译器不会报错。

但是,我发现不同编译器之间存在差异,我很想知道标准本身的要求。

考虑以下代码:

#include <iostream>

class Foo
{
public:

template <class T>
void bar(T v)
{
do_something(v);
}
};

void do_something(std::string s)
{
std::cout << "do_something(std::string)" << std::endl;
}

void do_something(int x)
{
std::cout << "do_something(int)" << std::endl;
}

int main()
{
Foo f;
f.bar("abc");
f.bar(123);
}

注意模板成员函数Foo::bar调用名为 do_something不依赖参数的全局函数甚至还没有被宣布。

然而,GCC 4.6.3 将愉快地编译上述程序。运行时,输出为:

do_something(std::string)
do_something(int)

Here's an ideone link .

因此,编译器似乎将标识符查找延迟到模板实例化之后,此时它能够找到 do_something .

相比之下,GCC 4.7.2 不会编译上述程序。它会产生以下错误:

test.cc: In instantiation of ‘void Foo::bar(T) [with T = const char*]’:
test.cc:27:13: required from here
test.cc:10:3: error: ‘do_something’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
test.cc:19:6: note: ‘void do_something(int)’ declared here, later in the translation unit

因此,GCC 4.7.2 知道 do_something稍后声明,但拒绝编译程序,因为 do_something不依赖于参数。

因此,我假设 GCC 4.7.2 在这里可能是正确的,而 GCC 4.6.3 是不正确的。所以大概,我需要声明 do_something之前 Foo::bar被定义为。这个问题是假设我想允许我类(class)的用户Foo扩展 Foo::bar 的行为通过实现自己的 do_something 重载.我需要写这样的东西:

#include <iostream>

template <class T>
void do_something(T v)
{
std::cout << "do_something(T)" << std::endl;
}

class Foo
{
public:

template <class T>
void bar(T v)
{
do_something(v);
}
};

void do_something(int x)
{
std::cout << "do_something(int)" << std::endl;
}

int main()
{
Foo f;
f.bar("abc");
f.bar(123);
}

这里的问题是 do_something 的重载从内部看不到 Foo::bar ,因此从未调用过。所以即使我调用do_something(int) , 它会调用 do_something(T)而不是 int 的过载.因此,对于 GCC 4.6.3 和 GCC 4.7.2,上述程序输出:

do_something(T)
do_something(T)

那么这里有哪些解决方案呢?我如何允许用户扩展 Foo::bar通过实现自己的 do_something 重载?

最佳答案

就重载 do_something 而言,您需要专门化您的原始模板:

template<>
void do_something<int>(int x) {
std::cout << "do_something(int)" << std::endl;
}

编辑:作为@MatthieuM。指出,如果您还需要重载函数(并且在某些时候您可能需要重载,因为函数模板不能部分特化),函数模板特化会产生奇怪的结果。请参阅 Matthieu 指向 Herb Sutter 文章的链接 Why Not Specialize Function Templates?以获得完整的解释。

建议改为使用包装在结构中的静态函数,它允许部分特化并消除重载函数模板带来的名称解析问题。

template<typename T>
struct DoSomething {
static void do_something(T v) {
std::cout << "do_something(T)" << std::endl;
}
};

struct Foo
{
template <class T>
void bar(T v) {
DoSomething<T>::do_something(v);
}
};

// Now you can specialize safely
template<>
struct DoSomething<int> {
static void do_something(int v) {
std::cout << "do_something(int)" << std::endl;
}
};

关于c++ - 模板内的参数相关查找,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16084984/

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