我正在尝试实现自己的std::variant
,偶然发现了一个问题。
以下代码定义了一个struct A
,它使用可变参数模板参数。该类提供了一种方法A::something()
,该方法只能使用出现在其模板参数中的类型来调用。但是编译器总是使用首先指定的类型来调用该方法:
#include <iostream>
using namespace std;
template <typename ...>
class A;
// Handle the edge case.
template <>
struct A<> { };
// Required so that `something()` can only be called with a type
// that appears in the template arguments.
template <typename T, typename ...TS>
struct A<T, TS...> : public A<TS...> {
void something(T) {
// Figure out which method was called.
cout << __PRETTY_FUNCTION__ << endl;
}
};
int main() {
A<char, short> a;
int b = 10;
// Will always call `A<char, short>::something()` (with T = char).
a.something(b);
}
因此,我添加了另一个抽象级别,允许用户显式指定类型:
#include <type_traits>
#include <iostream>
using namespace std;
template <typename ...>
class A;
// Handle the edge case.
template <>
struct A<> { };
// Required so that `something()` can only be called with a type
// that appears in the template arguments.
template <typename T, typename ...TS>
struct A<T, TS...> : public A<TS...> {
// Allow user to explicitly specify T.
template <typename A = T>
void something(A, std::enable_if_t<std::is_same_v<A, T>>* = 0) {
// Figure out which method was called.
cout << __PRETTY_FUNCTION__ << endl;
}
};
int main() {
A<char, short> a;
// Explicitly call `A<char, short>::something(char)`
a.something<char>(10); // works
// Explicitly call `A<short>::something(short)`
a.something<short>(10); // error
}
但是编译器无法找出要调用的方法(仅第一个有效):
0002.cpp: In function ‘int main()’:
0002.cpp:31:26: error: no matching function for call to ‘A<char, short int>::something<short int>(int)’
a.something<short>(10); // error
^
0002.cpp:18:10: note: candidate: template<class A> void A<T, TS ...>::something(A, std::enable_if_t<is_same_v<A, T> >*) [with A = A; T = char; TS = {short int}]
void something(A, std::enable_if_t<std::is_same_v<A, T>>* = 0) {
^~~~~~~~~
0002.cpp:18:10: note: template argument deduction/substitution failed:
我猜编译器无法区分方法,而在继承时仅覆盖前一个方法。