考虑以下代码,其中一个仿函数derived
继承自两个基类base1
和base2
,每个基类提供不同的重载:
// Preamble
#include <iostream>
#include <functional>
#include <type_traits>
// Base 1
struct base1 {
void operator()(int) const {
std::cout << "void base1::operator()(int) const\n";
}
void operator()(double) const {
std::cout << "void base1::operator()(double) const\n";
}
template <class Arg, class... Args>
void operator()(const Arg&, Args&&...) const {
std::cout << "void base1::operator()(const Arg&, Args&&...) const\n";
}
};
// Base 2
struct base2 {
void operator()(int) {
std::cout << "void base2::operator()(int)\n";
}
void operator()(double) {
std::cout << "void base2::operator()(double)\n";
}
};
// Derived
struct derived: base1, base2 {
using base1::operator();
using base2::operator();
void operator()(char) {
std::cout << "void derived::operator()(char)\n";
}
};
// Call
template <class F, class... Args>
void call(F&& f, Args&&... args) {
std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
}
// Main
int main(int argc, char* argv[]) {
const derived d1;
derived d2;
derived d3;
call(d1, 1); // void base1::operator()(int) const
call(d2, 1); // void base2::operator()(int)
call(d1, 1, 2); // void base1::operator()(const Arg&, Args&&...) const
call(d2, 1, 2); // void base1::operator()(const Arg&, Args&&...) const
call(d3, 'a'); // void derived::operator()(char)
return 0;
}
结果输出为:
void base1::operator()(int) const
void base2::operator()(int)
void base1::operator()(const Arg&, Args&&...) const
void base1::operator()(const Arg&, Args&&...) const
void derived::operator()(char)
说明了根据参数,所选的重载可以来自base1
,base2
或derived
。
我的问题是:是否有可能在编译时通过创建一个类型特征来检测哪个类提供了所选的重载?
这将具有以下形式:
template <
class Base1, // Possibly cv-ref qualified base1
class Base2, // Possibly cv-ref qualified base2
class Derived, // Possibly cv-ref qualified derived
class... Args // Possibly cv-ref qualified args
>
struct overload_origin {
using base1 = std::decay_t<Base1>;
using base2 = std::decay_t<Base2>;
using derived = std::decay_t<Derived>;
using type = /* base1, base2, or derived * /
};
并且在前面示例代码中的call
函数中使用时,会overload_origin::type
引用base1
,base2
,base1
,{{ 1}},base1
用于示例代码中说明的五个调用。
如何用模板元编程实现这样的事情?
答案 0 :(得分:3)
您可以从derived
和base1
派生一个班级。这样,来自operator()
的所有base1
来电都不明确:
struct derived_check: base1, derived {
using base1::operator();
using base2::operator();
};
// Main
int main(int argc, char* argv[]) {
const derived_check d1;
derived_check d2;
derived_check d3;
call(d1, 1); // error:ambiguous
call(d2, 1); // OK
call(d1, 1, 2); // error:ambiguous
call(d2, 1, 2); // error:ambiguous
return 0;
}
然后您可以使用基本检测技巧来创建检测类型特征。