C ++编译时检查可以使用某种类型的参数调用重载函数

时间:2018-07-18 14:34:39

标签: c++

考虑重载函数

void f(int);
void f(long);
void f(double);
void f(MyClass);

还有模板类中参数类型未知的方法

template <class T>
struct C {
  void method(T arg) { ... }
};

我想在编译时检查是否有f的版本可以将arg作为参数。

template <class T>
struct C {
  void method(T arg) { 
    if (CAN_BE_CALLED(f, arg) {
      f(arg);
    } else {
      g();
    }
  }
};

有可能这样做吗?我尝试了thisthis,但是编译器抱怨无法解析的重载函数类型

2 个答案:

答案 0 :(得分:3)

您可以使用detection idiom进行这样的测试

template<typename = void, typename... Args>
struct test : std::false_type {};

template<typename... Args>
struct test<std::void_t<decltype(f(std::declval<Args>()...))>, Args...>
    : std::true_type {};

template<typename... Args>
inline constexpr bool test_v = test<void, Args...>::value;

并将其用作

template <class T>
struct C
{
    void method(T arg)
    { 
        if constexpr (test_v<T>)
            f(arg);
        else
            g();
    }
};

Live

或者

template<typename... Args>
using test_t = decltype(f(std::declval<Args>()...));

template<typename... Args>
inline constexpr auto test_v = std::experimental::is_detected_v<test_t, Args...>;

答案 1 :(得分:2)

您可以对SFINAE执行以下操作:

template <class T, typename Enabler = void>
struct C {
    void method(T arg) {
        g();
    }
};

template <class T>
struct C<T, std::void_t<decltype(f(std::declval<T>()))>> {
    void method(T arg) { 
        f(arg);
    }
};

Demo