我正在尝试创建一个具有一些复杂的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
的数组之外进行排序。
答案 0 :(得分:4)
有关模板中名称查找的规则,详细here:
对于模板定义中使用的从属名称,将推迟查找直到知道模板参数为止,这时ADL将检查从模板定义上下文以及模板中可见的函数声明[...]实例化上下文,而非ADL查找仅检查从模板定义上下文可见的函数声明(换句话说,在模板定义之后添加新的函数声明不会使其可见,除非通过ADL < / strong>)。
因此有两个选项供您选择:
用户只能使用具有您提供的专业化参数(默认情况下)或可以通过Argument Dependent Lookup找到的参数来调用resolve
。基本上,它们必须在与其传递的类型相同的名称空间中定义其重载。
您将foo
设为用户可以专门研究的模板。您提供了自己的(默认)专长,用户可以稍后提供它们的专长,resolve
将为resolve
选择实例化时 可用的最佳模板专长(例如,{ {1}}被调用。)
附录:
标准库有一个非常相似的问题。参见例如here,了解如何进行自定义实现了resolve
用户的行为(允许)。特别要注意的是,在C ++ 20中,不再允许使用功能模板专业化(仅允许使用类模板专业化)。 the corresponding paper中详细说明了其原因。尽管上述建议对用户来说比在任何地方都要求类专业化更舒适,但是您可能应该研究标准库决定采取更极端立场的原因。