c++ - 使用可变函数模板的奇怪重载决议

标签 c++ c++11 language-lawyer variadic-templates overload-resolution

我有以下代码:

#include <iostream>

template <typename... Args>
void f(int a, int b, Args... args) { 
    std::cout << b << '\n';
    f(a, args...);
}
void f(int, int b) {
    std::cout << b << '\n';     
}

int main() {
  f(1, 2);
  //f(1, 2, 3);
}

同时 f(1, 2)编译,f(1, 2, 3)才不是。从编译器产生的错误消息中,我看到 f<>正在以某种方式实例化。在实例化中,调用 f(a)被犯了,因此是错误的。是什么让编译器不使用 f(int, int)但尝试实例化 f<>(int, int)在解析调用的过程中 f(1, 2, 3)

最佳答案

在可变函数模板中 f() , f在递归调用中是由于 [temp.dep] 而产生的从属名称,强调我的:

In an expression of the form:

postfix-expression ( expression-listopt)

where the postfix-expression is an unqualified-id, the unqualified-id denotes a dependent name if
(1.1) — any of the expressions in the expression-list is a pack expansion (14.5.3),

并且,根据 [temp.dep.res],强调我的:

In resolving dependent names, names from the following sources are considered:
(1.1) — Declarations that are visible at the point of definition of the template.
(1.2) — Declarations from namespaces associated with the types of the function arguments both from the instantiation context (14.6.4.1) and from the definition context.

f只有一个声明在 template <typename... Args> void f(int, int, Args...) 的定义点可见那就是它本身。第二点在这里不适用,因为你所有的论点都是 int s 并且基本类型没有关联的命名空间。由于无法使用单个参数调用该函数模板,因此会出现编译错误。

解决方案是重构您的代码,以便您的基本情况在定义点可见,即:

// this can be just the declaration
void f(int, int ) { /* ... */ } 

template <typename... Args>
void f(int a, int b, Args... args) 
{ 
    std::cout << b << '\n';
    f(a, args...); // now this will call f(int, int) 
                   // if sizeof...(Args) == 1
}

应用 (1.2) 的示例如下:

#include <iostream>

template <typename A, typename... Args>
void f(A a, int b, Args... args) { 
    std::cout << b << '\n';
    f(a, args...);
}

template <typename A>
void f(A a, int b) {
    std::cout << b << '\n';     
}

struct bar {};

int main() {
    //f(1,2,3);     // still doesn't compile, same reasoning
    f(bar{}, 2, 3); // OK. bar is in the global namespace, so declarations
                    // from the global namespace in both instantiation 
                    // and definition context are considered, which includes
                    // the second `f`.
}

关于c++ - 使用可变函数模板的奇怪重载决议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30066698/

相关文章:

c++ - Emscripten链接静态库错误: wasm streaming compile fail: Import 'env.getTempRet0'

c++ - 设置 Qt Widget 掩码

c++ - 查找 C++ 字符串中的第一个 printf 格式序列

c++ - 为什么 Boost.Range is_sorted 不需要前向迭代器?

c++ - C++ 如何区分对全局变量的调用和全局变量的声明?

c++ - C++ 标准中的何处定义了对不合格 *mem-initializer-id* 的查找?

c++ - 为什么是 `r(sqrt(x*x + y*y))` 而不是 `r(x)`

c++ - 使用openmp时出现编译错误

c++ - 静态或动态类型用于 "sizeof expr"?

c++ - 初始化器究竟是什么时候被临时销毁的?