模板:仅允许出现在模板参数中的类型

时间:2018-09-10 16:08:54

标签: c++ templates c++17 sfinae

我正在尝试实现自己的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:

我猜编译器无法区分方法,而在继承时仅覆盖前一个方法。

  1. 我的猜测正确吗?
  2. 我该如何解决这个问题?

此脚本应重现该问题:scriptoutput

0 个答案:

没有答案