简体   繁体   English

如何将不可复制类型的引用传递给 SFINAE“catch-all”重载 function?

[英]How to pass reference of noncopyable type to SFINAE "catch-all" overload function?

I want to handle noncopyable type by reference when SFINAE get unkown input, my code below can't work, is there a better way?当 SFINAE 获得未知输入时,我想通过引用处理不可复制类型,我下面的代码无法工作,有没有更好的方法?

#include <iostream>
#include <functional>

template<typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
void data_type(T const& t) {
    std::cout << "integer" << std::endl;
}

void data_type(...) {
    std::cout << "catch unknown" << std::endl;
}

int main() {
    struct noncopyable_type {
        int i;
        noncopyable_type() {}
        noncopyable_type(const noncopyable_type&) = delete;
    };

    int i;
    noncopyable_type s;

    // first try
    data_type(i);   // ok
    data_type(s);   // error: call to deleted constructor

    // try again
    data_type(std::cref(i)); // ok, but the type is std::reference_wrapper, not integer
    data_type(std::cref(s)); // ok
}

There are probably many ways, this is the first one that came to mind.可能有很多方法,这是第一个想到的。 Live demo现场演示

#include <iostream>
#include <functional>

template <typename T, 
          typename = typename std::enable_if<std::is_integral<T>::value>::type>
void data_type(T const& t) {
    std::cout << "integer" << std::endl;
}

template <typename ... T, 
          typename = typename std::enable_if<sizeof...(T)==1>::type>
void data_type(T const&...) {
    std::cout << "unknown" << std::endl;
}

int main() {
    struct noncopyable_type {
        noncopyable_type() {}
        noncopyable_type(const noncopyable_type&) = delete;
    };

    int i;
    noncopyable_type s;

    // first try
    data_type(i);   // ok
    data_type(s);   // ok
}

In C++17 I would just use if constexpr .在 C++17 我只会使用if constexpr

We rarely need to use the ... trick anymore.我们很少需要使用...技巧了。 With concepts, we can get the overload resolution behaviour we need without having to play tricks with the parameter declaration clause:有了概念,我们就可以得到我们需要的重载解析行为,而不必玩弄参数声明子句:

template <typename T>
requires std::integral<T>
void data_type(T const& t) {
    std::cout << "integer" << std::endl;
}

template <typename T>
void data_type(T const& t) {
    std::cout << "unknown" << std::endl;
}

The first overload is more constrained than the second one, so the second one will only be used when the first one is not applicable due to its constraint not being satisfied.第一个重载比第二个重载更受约束,因此第二个重载仅在第一个重载因未满足其约束而不适用时使用。

Note that the first overload may equivalently be written like so:请注意,第一个重载可以等效地写成这样:

template <std::integral T>
void data_type(T const& t) {
    std::cout << "integer" << std::endl;
}

It's very unclear to me what the actual problem you're trying to solve is, but there's a few possibly better ways to approach this.我非常不清楚您要解决的实际问题是什么,但是有一些可能更好的方法来解决这个问题。

With if constexpr使用 if constexpr

template <typename T>
void data_type(T const&) {
    if constexpr (std::is_integral_v<T>) {
        std::cout << "integral\n";
    } else {
        std::cout << "unknown\n";
    }
}

If (as I suspect) your goal is to not bind a reference to integral types (for whatever reason) you can get fancier with C++20 concepts如果(我怀疑)您的目标是不绑定对整数类型的引用(无论出于何种原因) ,您可以对 C++20 概念更加感兴趣

template <std::integral T>
void data_type(T) {
    std::cout << "integral\n";
}

template <typename T> requires (!std::integral<T>)
void data_type(T const&) {
    std::cout << "unknown\n";
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM