函数重载-定义顺序

时间:2018-12-12 17:29:52

标签: c++

我正在尝试创建一个具有一些复杂的resolve函数的库,该函数调用一个简单的foo函数。 resolve函数应适用于foo重载的任何类型。

库中提供的foo可以使用一些基本类型,但是我希望用户能够提供自己的foo的重载版本,可以在resolve中使用

这是一个非常简短的示例:

//IN THE LIBRARY
#include <iostream>

void foo(int i) { std::cout << "int " << i; }
void foo(float f) { std::cout << "float " << f; }

template <typename T>
void resolve(T arg) {
    //some complex computation
    foo(arg);
    //some more complutation
}

//IN THE USER CODE

void foo(const char* c) { std::cout << "cstring " << c; }

int main() {
    resolve(3);
    resolve(4.2f);
    resolve("abc");
    return 0;
}

问题是,foo的用户定义重载出现在resolve的定义之后,并且没有看到。我期望在实例化resolve<const char*>时会看到foo的3重载-但这似乎并非如此:

prog.cpp: In instantiation of ‘void resolve(T) [with T = const char*]’:
prog.cpp:16:15:   required from here
prog.cpp:8:5: error: invalid conversion from ‘const char*’ to ‘int’ [-fpermissive]
  foo(arg);
  ~~~^~~~~
prog.cpp:3:6: note:   initializing argument 1 of ‘void foo(int)’
 void foo(int i) { std::cout << "int " << i; }
      ^~~

所以,我的问题是,如何使它工作?是否有一些简单的方法可以让resolve的某些部分由用户提供(例如,在foo超载方面)?

一些约束:

  • 我希望在编译时解决它。
  • 在用户代码中应尽可能简单。例如,让resolve附加一个lambda参数(对于给定类型的arg应该始终相同)在使用中太复杂了。

使用场景类似于为给定的自定义std::less重载T,然后使用std::sort而不接受任何其他参数,除了应该T的数组之外进行排序。

1 个答案:

答案 0 :(得分:4)

有关模板中名称查找的规则,详细here

  

对于模板定义中使用的从属名称,将推迟查找直到知道模板参数为止,这时ADL将检查从模板定义上下文以及模板中可见的函数声明[...]实例化上下文,而非ADL查找仅检查从模板定义上下文可见的函数声明(换句话说,在模板定义之后添加新的函数声明不会使其可见,除非通过ADL < / strong>)。

因此有两个选项供您选择:

  • 用户只能使用具有您提供的专业化参数(默认情况下)或可以通过Argument Dependent Lookup找到的参数来调用resolve。基本上,它们必须在与其传递的类型相同的名称空间中定义其重载。

    示例:https://godbolt.org/z/KCaO-s

  • 您将foo设为用户可以专门研究的模板。您提供了自己的(默认)专长,用户可以稍后提供它们的专长,resolve将为resolve选择实例化时 可用的最佳模板专长(例如,{ {1}}被调用。)

    示例:https://godbolt.org/z/AYn7FM


附录:
标准库有一个非常相似的问题。参见例如here,了解如何进行自定义实现了resolve用户的行为(允许)。特别要注意的是,在C ++ 20中,不再允许使用功能模板专业化(仅允许使用类模板专业化)。 the corresponding paper中详细说明了其原因。尽管上述建议对用户来说比在任何地方都要求类专业化更舒适,但是您可能应该研究标准库决定采取更极端立场的原因。