SFINAE用于用户定义的转换

时间:2016-09-27 20:41:10

标签: c++ type-conversion sfinae

这个问题确实没有背景。

使用SFINAE(直接或间接使用type_traits)检查现有函数,成员函数等有很多种方法。但是:

第一个问题:有没有办法检查某个类是否实现了特定的用户定义转换运算符?

为了说明我的意思,请考虑此代码。我想在没有任何断言失败的情况下运行此代码:

#include <type_traits>
#include <cassert>

struct NotADouble {
};
struct Double {
    // explicit or not - you decide
    explicit operator double() {
        return 1.;
    }
};
// CORRECT THIS: ...
template<typename T,
    class = decltype(static_cast<double>(std::declval<T>()))>
int f(T) {
    return 1;
}
int f(...) {
    return 2;
}
// ... UNTIL HERE

int main() {
    assert(f(NotADouble()) == 2);
    assert(f(Double()) == 1);
    assert(f(3.) == 2);
    assert(f(3) == 2);
    assert(f(3.f) == 2);
}

f的当前实施检查是否存在从Tdouble的任何标准转换序列,我认为在这种情况下这与std::is_convertible相同。

另一种方法是以下实现,它接受前两个测试。

template<typename T>
int f(T, double (T::*)() = nullptr) {
    return 1;
}
int f(...) {
    return 2;
}

问题2 :即使NotADouble没有实现任何转换运算符,它似乎也允许这个成员函数指针。因此,double (T::*)()到底是什么以及为什么它存在于任何类中?

1 个答案:

答案 0 :(得分:0)

第一个问题:您可以创建辅助结构来检查给定结构中是否存在已定义的转换运算符(c ++ 14代码):

#include <type_traits>
#include <iostream>

struct NotDouble { };
struct Double {
   explicit operator double() {
       return 1.0;
   }
};

template <class From, class To, class = void>
struct HasConversionOperator: std::false_type { };

template <class From, class To>
struct HasConversionOperator<From, To, decltype((&From::operator To), void())>: std::true_type { };

template <class From, class To, class = void>
struct HasExplicitConversion: std::false_type {};

template <class From, class To>
struct HasExplicitConversion<From, To, decltype(std::declval<To&>() = (To)std::declval<From&>(), void())>: std::true_type { };

template <class From, class To, class = void>
struct HasImplicitConversion: std::false_type {};

template <class From, class To>
struct HasImplicitConversion<From, To, decltype(std::declval<To&>() = std::declval<From&>(), void())>: std::true_type { };

template <class T>
std::enable_if_t<HasConversionOperator<T, double>::value && HasExplicitConversion<T, double>::value && !HasImplicitConversion<T, double>::value> is_double(T d) {
   std::cout << "has conversion to double" << std::endl;
}

template <class T>
std::enable_if_t<!HasConversionOperator<T, double>::value || !HasExplicitConversion<T, double>::value || HasImplicitConversion<T, double>::value> is_double(T) {
   std::cout << "don't have conversion to double" << std::endl;
}

int main() {
   is_double(Double{});
   is_double(NotDouble{});
}

输出:

has conversion to double
don't have conversion to double

第二个问题: double (T::*)()是一种具有所有者T的任何成员函数指针,它返回一个不带任何参数的double。请记住,不仅转换运营商有这样的签名。更甚至,如果类T没有任何返回double的成员函数并且没有参数,则完全允许创建这样的指针类型,只是不能用任何值填充指针类型的变量...