构造函数超载和Sfinae



作为理解std::enable_if使用的一种练习,我尝试实现包装程序类(struct(以表示在任何给定时间点的特定类型:

#include<type_traits>
#include<typeinfo>
#include<iostream>
using std::enable_if;
using std::is_same;
using std::cout;
using std::endl;
template<typename T>
struct type_wrap{
                 type_wrap(typename enable_if<is_same<int,T>::value,T>::type&& rrT):value(rrT){
                         cout << "The wrapped type is " << typeid(value).name() << endl;
                         cout << "The wrapped value is " << value << endl;
                } 
                 type_wrap(typename enable_if<is_same<float,T>::value,T>::type && rrT):value(rrT){
                         cout << "The wrapped type is " << typeid(value).name() << endl;
                         cout << "The wrapped value is " << value << endl;
                 }
                 T& value;
};
int main(){
        type_wrap<int>(0);
        type_wrap<float>(0.5);
        return(0);
}

以上代码不编译:

so_main.cpp:16:47: error: no type named 'type' in 'std::__1::enable_if<false, int>'; 'enable_if' cannot be used to disable this declaration
                 type_wrap(typename enable_if<is_same<float,T>::value,T>::type && rrT):value(rrT){
                                              ^~~~~~~~~~~~~~~~~~~~~~~
so_main.cpp:26:9: note: in instantiation of template class 'type_wrap<int>' requested here
        type_wrap<int>(0);
        ^
so_main.cpp:12:47: error: no type named 'type' in 'std::__1::enable_if<false, float>'; 'enable_if' cannot be used to disable this declaration
                 type_wrap(typename enable_if<is_same<int,T>::value,T>::type&& rrT):value(rrT){
                                              ^~~~~~~~~~~~~~~~~~~~~
so_main.cpp:27:9: note: in instantiation of template class 'type_wrap<float>' requested here
        type_wrap<float>(0.5);
        ^
2 errors generated.

如果我要删除其中一个过载的构造函数,以及main()的相应实例化,则代码有效。但这打败了这项练习的全部目的。

有人可以指出汇编错误的原因吗?

sfinae在模板方法(/constructor(上工作,这是您的类是模板,您可以使用以下内容(即使在您的情况下专业化似乎更简单/更好(:

template<typename T>
struct type_wrap{
    template <typename U,
              std::enable_if_t<std::is_same<int, U>::value
                               && is_same<int, T>::value>* = nullptr>
    type_wrap(U arg) : value(arg){
        // Int case
        std::cout << "The wrapped type is " << typeid(value).name() << std::endl;
        std::cout << "The wrapped value is " << value << std::endl;
    }
    template <typename U,
              std::enable_if_t<std::is_same<float, U>::value
                               && is_same<float, T>::value>* = nullptr>
    type_wrap(U arg) : value(arg){
        // float case
        std::cout << "The wrapped type is " << typeid(value).name() << std::endl;
        std::cout << "The wrapped value is " << value << std::endl;
    }
    T value;
};

demo

有人可以指出汇编错误的原因吗?

因为std::enable_if将根据每种构造函数将您的一个构造函数非法:

type_wrap<int>(0);
type_wrap<float>(0.5);

intdouble将迫使std::is_same的另一侧具有false,在这种情况下std::enable_if没有type

template<bool B, class T = void>
struct enable_if {}; // int or float will get this on each constructor.
template<class T>
struct enable_if<true, T> { typedef T type; };

相反,使用模板专业化如下:

template<typename T>
struct type_wrap;
template<>
struct type_wrap<float>
{
    type_wrap(float&& rrT) :value(rrT) {
        cout << "The wrapped type is " << typeid(value).name() << endl;
        cout << "The wrapped value is " << value << endl;
    }
    float& value;
};
template<>
struct type_wrap<int>
{
    type_wrap(int&& rrT) :value(rrT) {
        cout << "The wrapped type is " << typeid(value).name() << endl;
        cout << "The wrapped value is " << value << endl;
    }
    int& value;
};

如果您的编译器支持C 17,则if constexpr使其变得更加容易,更直接:

template<typename T>
struct type_wrap
{
    type_wrap(T&& rrT):value(rrT)
    {
        if constexpr (std::is_same<int, T>::value)
        {
            cout << "The wrapped type is " << typeid(value).name() << endl;
            cout << "The wrapped value is " << value << endl;
        }
        else
        {
            cout << "The wrapped type is " << typeid(value).name() << endl;
            cout << "The wrapped value is " << value << endl;
        }
    } 
    T& value;
};

最新更新