静态/动态/常量/重新解释_可以在未评估的上下文中使用吗



我试图提供结构来检查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
                                  ^~~~~~~~~

实时

是否不允许在未评估的上下文中使用强制转换?

是否不允许在未评估的上下文中使用强制转换?

简短回答:是的,这是允许的。


无论如何,我会尽量把这个例子简化为一个最小的、有效的例子
请注意,强制转换表达式,除非明确相反,否则它们应与操作数未求值的运算符(sizeofnoexceptdecltypetypeid(一起使用。

例如,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 上观看直播

最新更新