enable_if SFINAE的问题

时间:2012-07-09 02:45:01

标签: c++ sfinae enable-if

在我写的一个程序中,我遇到了一些莫名其妙的SFINAE问题,所以我把它归结为一个独立的示例程序:

#include <type_traits>

struct Base { };

struct Derived : public Base { };

template<typename T>
struct From { };

template<typename T>
struct To {
    template<typename U>
    To(const From<U>& other) {
        static_assert(std::is_convertible<U*, T*>::value, "error");
    }
};

int main() {
    From<Derived> a;

    To<Base> b = a;
}

此程序编译时没有错误或警告。但是,这个:

#include <type_traits>

struct Base { };

struct Derived : public Base { };

template<typename T>
struct From { };

template<typename T>
struct To {
    template<typename U>
    To(const From<typename std::enable_if<true, U>::type>& other) {
    // this       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        static_assert(std::is_convertible<U*, T*>::value, "error");
    }
};

int main() {
    From<Derived> a;

    To<Base> b = a;
}

给出以下错误:

  

test.cpp:在函数int main()中:

     

test.cpp:22:18:错误:从From<Base>转换为非标量类型To<Derived>请求

这是因为我认为替换失败了,并且没有看到构造函数。

我在SFINAE上做错了,还是编译错误?我在Windows上使用rubenvb的GCC 4.7.1(如果它有所不同,则使用std=c++11。)

1 个答案:

答案 0 :(得分:3)

我使用默认模板参数,这样可以推导出参数:

#include <type_traits>

struct Base { };

struct Derived : public Base { };

template<typename T>
struct From { };

template<typename T>
struct To {
    template<typename U, class = typename std::enable_if<true, U>::type>
    To(const From<U>& other) {
    // this       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        static_assert(std::is_convertible<U*, T*>::value, "error");
    }
};

int main() {
    From<Base> a;

    To<Derived> b = a;
}

请注意,这导致static_assert失败,因为您反过来使用std::is_convertible。它应该是:

static_assert(std::is_convertible<T*, U*>::value, "error");

在您的示例中,无法推断模板类型U。在我的代码中,可以推导出它,因为它被用作构造函数中other参数的模板参数。在您的代码中,编译器会看到std::enable_if<true, U>::type,并且无法推断出U类型是什么。事件enable_if的结果被用作From的模板参数这一事实根本无济于事,因为U需要在此之前推断出来。