【问题标题】:C++ Compile-time check that an overloaded function can be called with a certain type of argumentC++ 编译时检查是否可以使用某种类型的参数调用重载函数
【发布时间】:2018-12-26 12:51:39
【问题描述】:

考虑一个重载函数

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

模板类中的一个方法,参数类型未知

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

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

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

有可能做到吗?我尝试了thisthis,但编译器抱怨未解决的重载函数类型

【问题讨论】:

  • 至少,if 需要是constexpr if。如果f(arg); 格式错误,编译器会抱怨它的存在,即使该分支永远不会被采用。使用constexpr if 可以解决这个问题。
  • 是否可以添加一个函数 f(),它采用任何类型并调用 g()。编译器将为您完成工作。我不知道该怎么做。可能是 void f(...){g();} ?
  • @WilliamJBagshaw template&lt;class T&gt; void f(T&amp;&amp;) { g(); } 听起来像您的建议。但是,当您使用 int&amp; 或其他几乎但不完全相同的参数调用时,它会变得很棘手。
  • @Mat: is_invocable 用重载调用有点问题...
  • 如果您难以将自己的测试创建为模板函数并填充专业。默认模板返回 false。可用类型返回 true。那么我认为如果你希望它们是假的,你也可以添加误报。您必须自己保持同步,并且获得所有误报可能是一个问题。但看起来自动方式也很困难。

标签: c++


【解决方案1】:

您可以使用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...>;

【讨论】:

  • @Jarod42 我正在考虑它,但不确定它的广泛使用/接受程度。
  • 它不适用于 GCC =\ 中的重载函数。但是如果将这些模板写在 函数声明之后,它就可以工作,这很少被接受。但在 MSVC 或没有重载函数的情况下效果很好。
【解决方案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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-12
    • 2015-02-19
    • 2021-11-13
    • 1970-01-01
    • 2014-05-17
    • 2013-09-19
    相关资源
    最近更新 更多