在模板中,如果从属名称是函数,则调用它

时间:2018-06-12 17:23:18

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

在我的TClass<T>::foo()函数中,当且仅当T是函数类型时,我才想调用T实例。

#include <iostream>
#include <functional>

template<class T>
struct TClass
{
    TClass(T value) : value(value) {}
    T value;
    void foo()
    {
        // if(value is std::function)
        //     call function;
    }
};

int main()
{
    TClass<int> t1{0};
    t1.foo();
    TClass<std::function<void()>> t2{[](){ std::cout << "Hello, World!\n"; }};
    t2.foo();
}

我该怎么做?

3 个答案:

答案 0 :(得分:7)

在C ++ 11中,最简单的方法是通过辅助函数重新推导出值:

template <typename U>
auto foo_helper(U const& f, int) -> decltype(f()) {
    return f();
}

template <typename U>
void foo_helper(U const&, long) {}

void foo() {
    foo_helper(value, 0);
}

0int的转换优于转换为long,因此如果第一次重载是可行的 - 那么它将是首选。如果第一次过载不可行,那么我们称之为第二次过载。

如果您真的只关心 关于std::function,那么我们可以有更简单的重载:

void foo_helper(std::function<void()> const& f) {
    f();
}

template <typename T>
void foo_helper(T const&) { }

void foo() {
    foo_helper(value);
}

答案 1 :(得分:4)

在C ++ 17中,你可以这样做:

void foo() {
    if constexpr (std::is_invocable_v<T>) {
        value();
    }
}

如果您只想允许std::function,那么您需要自己的特质,例如:

template <class T>
struct is_stdfunction: std::false_type {};

template <class T>
struct is_stdfunction<std::function<T>: std::true_type {};

template <class T>
constexpr bool is_stdfunction_v = is_stdfunction<T>::value;

// Then in foo():
void foo() {
    if constexpr (is_stdfunction_v<std::decay_t<T>>) {
        value();
    }
}

答案 2 :(得分:2)

为什么不partial specialization

考虑:

#include <iostream>
#include <functional>

template<class T>
struct TClass {
    TClass(T value) : value(value) {}
    T value;
    void foo() {
        std::cout << "T - other" << std::endl;
    }
};

template<class T>
struct TClass<std::function<T>> {
    TClass(std::function<T>  value) : value(value) {}
    std::function<T> value;
    void foo() {
        std::cout << "std::function" << std::endl;
    }
};