#c #c 17
#c #c 17
Вопрос:
Существует ли какая-либо безопасная std::any_cast
static_cast
комбинация и?
Я пытаюсь выполнить следующее:
#include <any>
#include <iostream>
int main( )
{
auto x = std::make_any< int >( 5 );
#if 0 // doesn't work
std::cout << std::any_cast< short >( x );
#else // works, but requires knowing the initial type
std::cout << static_cast< short >( std::any_cast< int >( x ) );
#endif
}
Комментарии:
1. Тип
x
isstd::any
. Этоstd::any_cast<stored_type>
предпочтительный и самый безопасный способ, что бы это ни значило при использовании std::any .
Ответ №1:
Единственный способ получить значение из std::any
any_cast<T>
where T
имеет то typeid
же значение, что и значение внутри (вы можете проверить его с .type()
помощью метода).
Если вам нужна другая семантика, например, «принять значение, если оно преобразуется в int
«, вы должны использовать что-то другое для стирания типа. Например, вы можете написать его самостоятельно.
Комментарии:
1. Как можно было бы написать свои собственные
std::any
с такой функциональностью? Как отслеживатьstatic_cast
конверсии? Или они должны быть жестко запрограммированы?2. @j5w Я подозреваю , что выступление Артура О’Дуайера на CppCon 2019 «Назад к основам» о стирании типов дает хороший обзор, хотя я сам его не смотрел
3. Отличное видео! В нем даже рассматривается подход к предоставлению
dynamic_cast
возможностей. К сожалению, он ничего не решаетstatic_cast
, поэтому мне может потребоваться жестко запрограммировать его и отслеживатьtypeid
вместо того, чтобы полагаться на vtables или RTTI модели исключений.4. @j5w Я рассматриваю
static_cast
просто еще одну возможность. Например.virtual optional<int> try_static_cast_to_int()
и в реализации есть две ветви: одна для конвертируемой, одна для всех остальных. Вы можете различать два сif constexpr
помощью иstd::is_convertible
во внутреннем шаблонном классе.
Ответ №2:
Дело в том, что std::any
это не может иметь смысла в данных, которые хранятся.
Вы можете подумать, что существует функция-член type()
, поэтому std::any
можете знать тип. Но на самом деле это не помогает, потому что единственное, что вы можете сделать с результатом type()
, это сравнить его с каким-либо другим typeid . То есть вы уже должны знать, для какого типа вы проверяете. Следовательно, std::any
не может действительно ответить на вопрос «какой тип вы носите?»; он может ответить только на вопрос «вы носите этот тип X?».
Последнее происходит при вызове std::any_cast<short>
: std::any
только знает, что он не несет a short
, но на самом деле не знает, что он несет тип, который можно преобразовать short
.
Комментарии:
1. Можно ли в любом случае создать такое автоматическое приведение в качестве расширения
std::any
, поскольку такое приведение выполняется во время компиляции?2. @j5w Нет, вы не можете, потому что вы должны расширяться в двух точках: а) в
any_cast
; б) во всех вызовах конструктораstd::any
, которые теоретически могут быть вне вашего контроля.