【问题标题】:Generalizing is_detected with variadic function parameters用可变参数函数泛化 is_detected
【发布时间】:2023-03-09 06:32:01
【问题描述】:

我正在尝试修改 is_detected 成语以允许将可变参数传递给它。我需要这个,因为我检测到的一些成员函数将具有用户提供的参数。

到目前为止,这就是我的工作。您将额外的参数提供给is_detected_args_v,理论上,模板专业化会启动并正确编译。从而给std::true_type

#include <type_traits>
#include <cstdio>

// slightly modified (and simplified) is_detected
template <template <class, class...> class Op, class T, class = void, class...>
struct is_detected_args : std::false_type {};
template <template <class, class...> class Op, class T, class... Args>
struct is_detected_args<Op, T, std::void_t<Op<T, Args...>>, Args...>
        : std::true_type {};

template <template <class, class...> class Op, class T, class... Args>
inline constexpr bool is_detected_args_v
        = is_detected_args<Op, T, Args...>::value;

// has_func, checks the function starts with int, and then Args&...
template <class T, class... Args>
using has_func = decltype(std::declval<T>().func(
        std::declval<int>(), std::declval<Args&>()...));


// has the func
struct obj {
    void func(int, double&, double&) {
        printf("potato\n");
    }
};

int main(int, char**) {
    obj o;

    if constexpr(is_detected_args_v<has_func, obj, double, double>) {
        double d = 0;
        double d2 = 42;
        o.func(42, d, d2);
    }
}

您可以在此处运行示例(在所有 3 个编译器上测试):https://wandbox.org/permlink/ttCmWSVl1XVZjty7

问题是,永远不会选择专业化并且条件总是错误的。我的问题有两个方面。

  1. 这可能吗?
  2. 为什么is_detected 不专业化?

谢谢

【问题讨论】:

    标签: c++ templates c++17 template-meta-programming sfinae


    【解决方案1】:

    这里的主要问题是误解了void_t 的作用。作为复习,请参阅how does void_t work?。关键思想是主模板有一个void 参数,而特化有一些你想要检查的复杂的东西包裹在void_t 中,以便它匹配主模板的参数。您的示例中没有发生这种情况。

    我们可以通过两个简单的步骤来修复它。首先,你有这个类型 TArgs... 实际上没有任何理由将其拆分,如果我们没有无关参数,则更容易查看。因此,您的尝试只是减少了(我还为应该是 void 的参数命名):

    template <template <class...> class Op, class AlwaysVoid, class...>
    struct is_detected_args : std::false_type {};
    template <template <class...> class Op, class... Args>
    struct is_detected_args<Op, std::void_t<Op<Args...>>, Args...>
            : std::true_type {};
    
    template <template <class...> class Op, class... Args>
    inline constexpr bool is_detected_args_v = is_detected_args<Op, Args...>::value;
    

    现在应该更容易看到缺少的内容:void 参数!你没有传递void,你需要传递。不过,这很容易解决:

    template <template <class...> class Op, class... Args>
    inline constexpr bool is_detected_args_v = is_detected_args<Op, void, Args...>::value;
    //                                                              ~~~~~
    

    现在它按预期工作了。


    Cppreference 还提供了is_detected 的完整实现,如果你也想看看的话。

    【讨论】:

    • 太棒了!谢谢你的详细解释:)
    猜你喜欢
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    相关资源
    最近更新 更多