1

我在编写的程序中遇到了一些莫名其妙的 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如果它有所作为)。

4

1 回答 1

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构造函数中参数的模板参数。在您的代码中,编译器看到 astd::enable_if<true, U>::type并且无法推断出该U类型是什么。结果enable_if被用作模板参数这一事实From根本没有帮助,因为U需要在此之前推导出来。

于 2012-07-09T02:59:30.943 回答