我试图提供结构来检查A
是否可(选择强制转换(为B
。除了名称之外,所有四个强制转换都将具有完全相同的实现(可以进行本地宏定义,但不是必需的(。我为操作员结构写了很多检查,例如:
#include <iostream>
#include <type_traits>
#include <string>
template<class, class, class, class = void>
struct is_valid_ternary_operator : std::false_type
{ };
template<class T, class S, class R>
struct is_valid_ternary_operator <T, S, R,
std::void_t<decltype(std::declval<T>() ?
std::declval<S>() :
std::declval<R>())>> : std::true_type
{ };
int main()
{
//true? 1 : 0 //is ok
std::cout << is_valid_ternary_operator<bool, int, int>::value << std::endl;
//true? 1 : std::string("0") //would be error
std::cout << is_valid_ternary_operator<bool, int, std::string>::value << std::endl;
//true? std::string("1") : std::string("0") //ok
std::cout << is_valid_ternary_operator<bool, std::string, std::string>::value << std::endl;
//std::string("1")? 1 : 0 //error
std::cout << is_valid_ternary_operator<std::string, int, int>::value << std::endl;
}
实例
将显示预期的输出。但现在考虑对演员阵容做同样的事情:
template<class T, class S, class = void>
struct is_static_cast_able : std::false_type
{ };
template<class T, class S>
struct is_static_cast_able<T, S,
std::void_t<decltype(static_cast<std::declval<S>()>
(std::declval<T>()))>> : std::true_type
{ };
但它会产生错误:
main.cpp:12:84: error: template argument 1 is invalid
(std::declval<T>()))>> : std::true_type
^~
main.cpp:12:94: error: template argument 3 is invalid
(std::declval<T>()))>> : std::true_type
^~~~~~~~~
实时
是否不允许在未评估的上下文中使用强制转换?
是否不允许在未评估的上下文中使用强制转换?
简短回答:是的,这是允许的。
无论如何,我会尽量把这个例子简化为一个最小的、有效的例子
请注意,强制转换是表达式,除非明确相反,否则它们应与操作数未求值的运算符(sizeof
、noexcept
、decltype
、typeid
(一起使用。
例如,sizeof
是一个未评估的上下文:
int main() {
unsigned int i;
sizeof(static_cast<int>(i));
}
一个简单得多的例子,它是有效的
使用decltype
也可以显示相同的情况,其操作数也未求值:
int main() {
unsigned int i;
decltype(static_cast<int>(i)) j = i;
}
等等,我们可以用noexcept
:做一些类似的事情
int main() {
unsigned int i;
bool b = noexcept(static_cast<int>(i));
}
与typeid
:
#include <typeinfo>
int main() {
unsigned int i;
auto b = typeid(static_cast<int>(i)).name();
}
is_static_castable<T, S>
听起来像是C++标准库中已经存在的东西。作为CCD_ 12。
对于您的问题:static_cast
并不总是意味着编译时间。例如,在整数类型和浮点类型的转换中,如果编译器在编译时无法发出转换代码,则可以选择发出转换代码。虽然它在很大程度上可以出现在未经评估的环境中。
C++中未赋值的操作数非常有限:上下文是:
decltype
sizeof
typeid
noexcept
引用C++标准草案[Epr/8]
在一些上下文中出现未赋值的操作数(
[expr.typeid]
,[expr.sizeof]
、[expr.unary.noexcept]
、[dcl.type.simple]
(。一未求值的操作数不求值。未求值的操作数是被认为是一个完整的表达。
注:std::is_convertible
不包括static_cast
的所有情况
因此,为了完整性,这就是您想要对is_static_cast_able
进行的操作,它几乎涵盖了static_cast
:的所有情况
template<class T, class S, class = void>
struct is_static_cast_able : std::false_type
{ };
template<class T, class S>
struct is_static_cast_able<T, S,
std::enable_if_t<
std::is_convertible<T, S>::value ||
std::is_base_of<std::decay_t<T>, std::decay_t<S>>::value ||
std::is_base_of<std::decay_t<S>, std::decay_t<T>>::value ||
std::is_base_of<std::remove_pointer_t<T>, std::remove_pointer_t<S>>::value ||
std::is_base_of<std::remove_pointer_t<S>, std::remove_pointer_t<T>>::value ||
(std::is_same<T, void*>::value && std::is_pointer<S>::value) ||
(std::is_same<S, void*>::value && std::is_pointer<T>::value)
>
>
: std::true_type { };
以下测试代码通过:
struct A {};
struct B : public A {};
int main()
{
static_assert(is_static_cast_able<int, char>::value, "");
static_assert(is_static_cast_able<double, int>::value, "");
static_assert(is_static_cast_able<int, double>::value, "");
static_assert(is_static_cast_able<void*, double*>::value, "");
static_assert(is_static_cast_able<double*, void*>::value, "");
static_assert(is_static_cast_able<B, A>::value, "");
static_assert(is_static_cast_able<A, B>::value, "");
static_assert(is_static_cast_able<B&, A&>::value, "");
static_assert(is_static_cast_able<B*, A*>::value, "");
static_assert(is_static_cast_able<A&, B&>::value, "");
static_assert(is_static_cast_able<A*, B*>::value, "");
}
在Coliru 上观看直播