static/dynamic/const/reinterpret_cast 可以在未计算的上下文中使用吗?
Can static/dynamic/const/reinterpret_cast be used in unevaluated context?
我试图提供用于检查的结构 A
是否(选择强制转换)- 可强制转换为 B
。
所有四个强制类型转换都将具有完全相同的实现,期望它们的名称(本地宏定义是可能的,但不是必需的)。我写了很多 check-for operators 结构,例如:
#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
^~~~~~~~~
是否不允许在未计算的上下文中使用强制转换?
Is using casts in unevaluated context not allowed?
简短回答:是的,这是允许的。
无论如何,我会尝试将示例简化为最小的工作示例。
请注意 casts 是 expressions 并且它们应该与操作数未评估的运算符一起工作(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++ 标准库中已经存在的东西。作为 std::is_convertible
.
关于您的问题:static_cast
并不总是意味着编译时间。例如,在整数和浮点类型的转换中,如果编译器无法在编译时执行转换,则编译器可能会选择发出转换代码。尽管。它很可能出现在未评估的上下文中。
C++ 中未计算的操作数非常有限:
上下文是:
decltype
sizeof
typeid
noexcept
引用C++标准草案,[expr/8]
In some contexts, unevaluated operands appear ([expr.typeid]
,
[expr.sizeof]
, [expr.unary.noexcept]
, [dcl.type.simple]
). An
unevaluated operand is not evaluated. An unevaluated operand is
considered a full-expression.
注意: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, "");
}
我试图提供用于检查的结构 A
是否(选择强制转换)- 可强制转换为 B
。
所有四个强制类型转换都将具有完全相同的实现,期望它们的名称(本地宏定义是可能的,但不是必需的)。我写了很多 check-for operators 结构,例如:
#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
^~~~~~~~~
是否不允许在未计算的上下文中使用强制转换?
Is using casts in unevaluated context not allowed?
简短回答:是的,这是允许的。
无论如何,我会尝试将示例简化为最小的工作示例。
请注意 casts 是 expressions 并且它们应该与操作数未评估的运算符一起工作(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++ 标准库中已经存在的东西。作为 std::is_convertible
.
关于您的问题:static_cast
并不总是意味着编译时间。例如,在整数和浮点类型的转换中,如果编译器无法在编译时执行转换,则编译器可能会选择发出转换代码。尽管。它很可能出现在未评估的上下文中。
C++ 中未计算的操作数非常有限: 上下文是:
decltype
sizeof
typeid
noexcept
引用C++标准草案,[expr/8]
In some contexts, unevaluated operands appear (
[expr.typeid]
,[expr.sizeof]
,[expr.unary.noexcept]
,[dcl.type.simple]
). An unevaluated operand is not evaluated. An unevaluated operand is considered a full-expression.
注意: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, "");
}