为什么允许ADL查找模板名称绑定?

时间:2016-05-28 12:35:58

标签: c++

我知道依赖名称,必须将绑定推迟到实例化点。 请考虑以下代码:

#include <iostream>

using namespace std;

template <class T> 
void g(T a)
{
    f(a);
}

namespace MyNamespace
{
    class X{};
    void f(X) {  cout << "f(X)\n"; }
}

void f(int i) { cout << "f(int)\n"; }

int main()
{
    g(MyNamespace::X{});   //1. print f(x)
    //g(1);                //2. not compile
    return 0;
} 

为1,我测试的所有编译器(VC ++,gcc,clang)都可以通过ADL找到MyNamespace :: f(X)。没关系,这符合标准。但是,gcc和clang无法编译2.因为标准不允许直接在实例化上下文中搜索函数。这是标准要求(Fine,vc ++违反了这方面的标准)。

我知道标准不允许在模板实例化环境中搜索功能是ODR的安全措施。但是,为什么它允许ADL检查从模板实例化上下文中可见的函数声明?这会导致违反ODR吗?请考虑以下内容:

//ff.h
#include <iostream>

namespace N
{
    class X {};
    int g(X, int i);
}

template<typename T>
double ff(T t, double d)
{
    return g(t, d);
}

//ff.cpp
#include "ff.h"

int N::g(X, int i) { std::cout << "g(X,int)" << std::endl; return i; }

double x1 = ff(N::X{}, 1.1);

//main.cpp
#include "ff.h"

namespace N
{
    double g(X, double d) { std::cout << "g(X,double)" << std::endl; return d; }
}

auto x2 = ff(N::X{}, 2.2);

int main()
{
    extern double x1;
    std::cout<<"x1 = " << x1 << std::endl;
    std::cout << "x2 = " << x2 << std::endl;
    return 0;
}

有两个地方实例化函数模板ff:ff(N::X, double),一个在ff.cpp中,一个在main.cpp中。在main.cpp中,命名空间被更改,并且在实例化ff之前在main.cpp中添加了更好的匹配函数double g(X, double)。因此,main.cpp中的实例化可以获得这个更好的匹配函数g,无论如何g在main.cpp的范围内是相等的。但是ff.cpp中的实例化只能选择ff.h中声明的第一个g。这显然违反了ODR,虽然我测试了所有3个编译器选择了int g(X, int),但这似乎编译器足够聪明,可以在生成的代码中检测到这种疾病,并优化了重复的专业化。编制者没有义务发现这类问题。那么为什么标准允许在这种情况下使用ADL,这可能会导致对ODR的潜在违规?

0 个答案:

没有答案