Variadic模板选择更常见的模板而不是重载

Sta*_*ght 3 c++ templates variadic-templates c++11

想象一下这段代码:

#include <iostream>
void PrintInternal() {
    std::cout << std::endl;
}

template <typename T, typename...ARGS>
void PrintInternal(const T& head, const ARGS&...rest) {
    std::cout << head << " ";
    PrintInternal(rest...);
};

template <typename...ARGS>
void PrintInternal(const double& head, const ARGS&...rest) {
    std::cout << "DBL!!! " << head << " ";
    PrintInternal(rest...);
}

template <typename...ARGS>
void Print(const ARGS&...args) {
    PrintInternal(args...);
}

int main() {
    Print(1.1, 2, 3.3, 4);
    Print(0, 1.1, 2, 3.3, 4);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

第一Print产出:

DBL!1.1 2 3.3 4

我的期望是,它会输出DBL!3.3之前或没有DBL !!! 一点都不 但为什么一个???

第二项Print产出:

0 1.1 2 3.3 4

为什么没有DBL !!! 如果我们在第一个例子中有一个输出就像输出一样.

以及如何实现,对于每一个double我将输出不同的东西而没有部分专业化?我想,简单的重载应该没问题......

链接到cpp.sh以查看编译结果 - > http://cpp.sh/42cz

Bar*_*rry 6

Lookup PrintInternal()将找到两种类型的函数:

  • 所有功能在功能模板定义时都可见.
  • 函数模板的从属参数的关联命名空间中的所有函数.

在这种情况下,我们的所有参数都是基本类型,因此没有任何关联的命名空间.这使事情变得更容易.所以当我们开始时:

#include <iostream>
void PrintInternal() { // #1
    std::cout << std::endl;
}

template <typename T, typename...ARGS>
void PrintInternal(const T& head, const ARGS&...rest) { // #2
    std::cout << head << " ";
    PrintInternal(rest...); // <== (*)
};

template <typename...ARGS>
void PrintInternal(const double& head, const ARGS&...rest) { // #3
    std::cout << "DBL!!! " << head << " ";
    PrintInternal(rest...);
}
Run Code Online (Sandbox Code Playgroud)

标记的呼叫PrintInteral()只有两个候选者:nullary函数(#1)和它自己(#2).另一个,更专业化PrintInteral()const double&(#3)尚未可见,因此从未被视为候选者.并不是#2比#3更受欢迎,只是它是唯一的选择.

如果你翻转两个重载的顺序,那么你会有一个不同的问题 - 你将无法找到#2!

这为您提供了一些选择:

  1. 单独打印单个元素以打印所有元素.这样,你只需要重载PrintSingle(),这更容易做到.
  2. 向前声明所有功能模板,以便它们全部可见.
  3. 引入另一个论点仅仅是为了最初应用的第二个要点.只是一个伪参数,只是用ADL进行名称查找.这个解决方案有时是必要的,但总是令人困惑:

    namespace N {
        struct adl { };
    
        void PrintInternal(adl ) {
            std::cout << std::endl;
        }
    
        template <typename T, typename...ARGS>
        void PrintInternal(adl, const T& head, const ARGS&...rest) {
            std::cout << head << " ";
            PrintInternal(adl{}, rest...);
        }
    
        template <typename...ARGS>
        void PrintInternal(adl, const double& head, const ARGS&...rest) {
            std::cout << "DBL!!! " << head << " ";
            PrintInternal(adl{}, rest...);
        }
    }
    
    template <typename...ARGS>
    void Print(const ARGS&...args) {
        PrintInternal(N::adl{}, args...);
    }
    
    Run Code Online (Sandbox Code Playgroud)