如何强制实例化类模板的成员函数?

时间:2018-12-18 08:53:03

标签: c++ c++11 templates sfinae

我最近发现,类模板的成员函数在使用之前不会实例化,这非常烦人,因为这会使某些SFINAE构造不起作用。我想知道如何确保始终在实例化类后立即实例化类模板专业化的成员函数-但仅使用类模板定义内的语句,以便如果不能实例化成员函数,SFINAE开始运行,并且编译器依靠常规类模板。

我计划使用的代码如下:

template <typename T, typename U>
class test_type {
    // general template; dummy parameter U is to allow specialization.
    static const bool value = false;
}

template <typename T>
class test_type<T, T> {
    // template specialization
    void f(T t) {
        // do all sorts of type-specific operations with t
        // (e.g., calling member functions)

        // if T is not suitable for these operations, I want
        // a substitution error to be generated so that the
        // general template is used instead
    }

    static const bool value = true;
}

template <typename T>
using satisfies = test_type<T, T>::value;

1 个答案:

答案 0 :(得分:5)

类中成员函数的主体将不属于SFINAE。模板将根据签名进行实例化,一旦实例化了类,错误的成员函数将导致硬错误。

您需要做的是构建一个type_trait,可以将其放置在模板专门化中。这是一个检查两个不同成员函数的玩具示例。

#include <iostream>
#include <type_traits>

template <typename T>
using check_for_method = std::void_t<decltype(std::declval<T>().run()), decltype(std::declval<T>().go())>;

template <typename T, typename U = void>
class test_type {
public:
    static const bool value = false;
};

template <typename T>
class test_type<T, check_for_method<T>> {
public:
    void f(T t) {
        t.run();
        t.go();
    }

    static const bool value = true;
};

struct Foo {
    void run() {
        std::cout << "Running\n";
    }
};

struct Bar : Foo {
    void go() {
        std::cout << "Going\n";
    }
};

int main() {
    test_type<Foo> t1;
    test_type<int> t2;
    test_type<Bar> t3;

    std::cout << t1.value << " " << t2.value << " " << t3.value << std::endl;
    t3.f(Bar{});
}