В шаблоне, если зависимое имя является функцией, вызовите ее - PullRequest
0 голосов
/ 12 июня 2018

В моей функции 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 голосов
/ 12 июня 2018

В 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();
    }
}
0 голосов
/ 12 июня 2018

Почему бы не частичная специализация ?

Рассмотрим:

#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;
    }
};
0 голосов
/ 12 июня 2018

В 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);
}

Преобразование из 0 в int лучше, чем егопреобразование в 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);
}
...