用于用户定义转换的 SFINAE
SFINAE for user-defined conversion
这个问题真的没什么背景。
有很多方法可以使用 SFINAE(直接或间接使用 type_traits)来检查现有函数、成员函数等。但是:
第一个问题:有什么方法可以检查class是否实现了特定的用户定义的转换运算符?
为了说明我的意思,请考虑这段代码。我想 运行 此代码没有任何断言失败:
#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
的当前实现检查是否存在从T
到double
的任何标准转换序列,我假设这与本例中的std::is_convertible
相同.
另一种方法是以下实现,它接受前两个测试。
template<typename T>
int f(T, double (T::*)() = nullptr) {
return 1;
}
int f(...) {
return 2;
}
问题2:虽然NotADouble没有实现任何转换运算符,但似乎允许这个成员函数指针。因此,double (T::*)()
到底是什么?为什么 class 存在?
第一个问题:您可以创建辅助结构来检查给定结构(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
是returns不带的double任何参数。请记住,不仅转换运算符具有这样的签名。更重要的是,即使 class T 没有任何 returns double 的成员函数并且不带参数,它完全允许创建这样的指针类型,只是无法填充变量具有任何值的指针类型...
这个问题真的没什么背景。
有很多方法可以使用 SFINAE(直接或间接使用 type_traits)来检查现有函数、成员函数等。但是:
第一个问题:有什么方法可以检查class是否实现了特定的用户定义的转换运算符?
为了说明我的意思,请考虑这段代码。我想 运行 此代码没有任何断言失败:
#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
的当前实现检查是否存在从T
到double
的任何标准转换序列,我假设这与本例中的std::is_convertible
相同.
另一种方法是以下实现,它接受前两个测试。
template<typename T>
int f(T, double (T::*)() = nullptr) {
return 1;
}
int f(...) {
return 2;
}
问题2:虽然NotADouble没有实现任何转换运算符,但似乎允许这个成员函数指针。因此,double (T::*)()
到底是什么?为什么 class 存在?
第一个问题:您可以创建辅助结构来检查给定结构(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
是returns不带的double任何参数。请记住,不仅转换运算符具有这样的签名。更重要的是,即使 class T 没有任何 returns double 的成员函数并且不带参数,它完全允许创建这样的指针类型,只是无法填充变量具有任何值的指针类型...