模板分辨率

问题描述 投票:3回答:1

在“Inside the C ++ Object Model”的第7章中,有人写道,nomember名称的解析取决于name的使用是否与“用于实例化模板的参数类型”有关。我写了一个测试:

/// -------------Test.h---------------
#ifndef TEST_H
#define TEST_H

#include <iostream>

using namespace std;

extern double foo(double t);

template <typename T>
class Test {
    public:
        void fun1() {
            member = foo(val);
        }
        T fun2() {
            return foo(member);
        }
    private:
        int val;
        T member;
};

#endif

/// -------------test1.cc-------------
#include <iostream>

using namespace std;

double foo(double t) {
    cout << "foo doule is called" << endl;
    return t;
}

int foo(int t) {
    cout << "foo int is called" << endl;
    return t;
}
-------------test.cc--------------
#include "Test.h"

extern int foo(int t);

int main() {
    Test<int> fi;
    fi.fun1();
    fi.fun2();
    return 0;
}

我希望“foo double被称为\ n foo int被称为”,但我得到了“foo double被称为\ n foo double被称为”。我的g ++版本如下。如果你能帮助我,我会很感激的。

My g++ version

c++ templates resolution
1个回答
3
投票

我担心这本书不是描绘完整的画面(并且它有点老化)。是的,foo(member)是一个依赖于模板参数的函数调用。但是在[temp.dep.candidate]的C ++标准中描述了在模板中查找函数的具体方法:

对于postfix-expression是从属名称的函数调用,使用通常的查找规则([basic.lookup.unqual],[basic.lookup.argdep])找到候选函数,除了:

  • 对于使用非限定名称查找的查找部分,仅找到模板定义上下文中的函数声明。
  • 对于使用关联命名空间([basic.lookup.argdep])查找的部分,仅找到在模板定义上下文或模板实例化上下文中找到的函数声明。

foo的重载可以通过两种方式之一查找。通过直接不合格的查找,并通过argument dependent lookup(又名ADL)。简单的非限定查找仅考虑模板定义点处已知的名称。由于您只声明了foo(double),这是在模板定义点找到的唯一重载。

在实例化时,编译器将尝试执行ADL以查找更多foo,但基本类型不会对ADL有所贡献。 int不能用来寻找foo(int)。所以编译器只能做一件事,将整数转换为double,并调用foo(double)

如果要测试编译器ADL,只需添加一个简单的用户定义类型和重载。例如:

enum E{};
E foo(E) {
  cout << "foo E is called\n";
  return {};
}

int main() {
    Test<E> fi;
    fi.fun1();
    fi.fun2(); 
    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.