static_cast: шаблоны функций преобразования - они действительно работают? - PullRequest
6 голосов
/ 23 октября 2019

Насколько я прочитал static_cast следующий код должен работать:

#include <iostream>
#include <string>

class ConvSample
{
public:
    template<typename T>
    constexpr operator T(){
        return {};
    }
};

int main()
{
    ConvSample aInst;

    int i = aInst;
    std::cout << i << "\n";

    std::string str = static_cast<std::string>(aInst);
    std::cout << str << "\n";

    return 0;
}

И он отлично работает с некоторыми компиляторами, такими как Clang. Но например с MSVC или ICC нет.

См. Проводник компилятора

Как правило, они жалуются на некоторую неоднозначность, вызванную неработающими конструкторами, предоставляемыми std :: string.

Кроме того, еслиЯ включаю Wconversion на gcc. Я получаю ошибку сегментации?!

Что-то не так в коде? Эти ошибки - просто ошибки компилятора? Если я изменю код, чтобы не использовать шаблоны, он будет работать очень хорошо: Проводник компилятора

1 Ответ

2 голосов
/ 23 октября 2019

Стандарт здесь, к сожалению, расплывчатый ([expr.static.cast] / 4, цитаты опущены):

Выражение e может быть явно преобразовано в тип T, если естьявляется неявной последовательностью преобразования из e в T, или если разрешение перегрузки для прямой инициализации объекта или ссылки типа T из e найдет хотя бы одну жизнеспособную функцию. […] [T] объект результата инициализируется напрямую из e. […]

Здесь выполняются оба разрешающих условия: есть неявная последовательность преобразования (состоящая из требуемого вызова функции преобразования), и есть несколько жизнеспособных функций для прямой инициализации (потому что естьтакже последовательности неявного преобразования для различных отдельных параметров для конструкторов std::string).

Однако, это только инициализация копии последовательности неявного преобразования, которая отказывается преобразовывать ConvSample в (скажем) const char* и затем std::string, что обеспечивает однозначное средство для создания std::string: оно специально ищет функции преобразования в целевой тип, и в то время как допускает преобразования в (скажем) const std::string&, общие реализации не интерпретируют это как означающее, что шаблон функции преобразования должен быть создан и для этого типа и стать неоднозначным.

Прямая инициализация, которая в конечном итоге требуется, неоднозначна среди *5 конструкторов с одним аргументом 1028 * (6 для std::string_view -как типы): ConvSample, конечно, может быть преобразован в тип параметра для любого из них с одинаковыми «затратами».

Компиляторы, которые принимают это, применяют правила инициализации копирования (но все еще допускают * 1033). * преобразования). Те, кто отвергают его, применяют прямую инициализацию, которая, как я полагаю, в настоящее время требует формулировки. Ссылка на последовательности неявного преобразования была введена только в C ++ 17 для CWG242 , и, очевидно, расхождение реализации сохраняется в этой области.

...