странное поведение компилятора g ++ для typeid внутри функции шаблона - PullRequest
0 голосов
/ 10 октября 2019

Я пытаюсь создать некоторую полиморфную функцию-шаблон члена класса для обработки нескольких типов:

class MyClass
{
public:
    template<typename T>
    void AddType(T value);
private:
    bool b_val;
    int i_val;
    std::string str_val;
}

template<typename T>
void MyClass::AddType(T value)
{    
    if(typeid(T) == typeid(bool))
    {        
        b_val = value;
    }
    else if(typeid(T) == typeid(int))
    {        
        i_val = value;
    }
    else if(typeid(T) == typeid(std::string))
    {
         str_val = val
    }
}

использование:

MyClass message;
std::string s = "string";
int i = 123;
message.AddType(s);
message.AddType(i);

по некоторым причинам я получаю ошибку компилятора:

error: assigning to 'bool' from incompatible type 'std::__cxx11::basic_string<char>'
        b_val = value;
                ^~~~~

note: in instantiation of function template specialization 'MyClass::AddType<std::__cxx11::basic_string<char> >' requested here
    message.AddType(s);

почему компилятор догадывается, что это std :: string?

Обновление: Воспроизводимая ошибка

Ответы [ 2 ]

4 голосов
/ 10 октября 2019

Причина вашей ошибки заключается в том, что if s по сути являются конструкциями времени выполнения, в то время как шаблоны являются конструкциями времени компиляции.

Что это действительно означает, что после компиляции ваша функция шаблона будет выглядеть примерно так:

void MyClass::AddType(std::string value)
{    
    if(some_value_for_typeid(std::string) == some_value_for_typeid(bool))
    {        
        b_val = value;
    }
    else if(some_value_for_typeid(std::string) == some_value_for_typeid(int))
    {        
        i_val = value;
    }
}

Давайте сделаем это еще яснее:

void MyClass::AddType(std::string value)
{    
    if(2 == 3)
    {        
        b_val = value;
    }
    else if(2 == 5)
    {        
        i_val = value;
    }
}

Стандарт, если для необходимо , чтобы иметь возможность управлять своим телом, в случае, если условие когда-либо будетправда. Таким образом, это компилируется, и это терпит неудачу.


Что можно сделать с этим? Существует несколько вариантов.

Наиболее близким к вашему решению является использование нового C ++ 17 if constexpr. Эта конструкция действует точно так же, как обычный if, только то, что оценивается во время компиляции. Недостатком является то, что выражение должно быть возможным для оценки во время компиляции (оно должно быть выражением constexpr), а operator== для std::type_info (вещь, возвращаемая typeid) не является constexpr. Но есть std::is_same, который выполняет сравнение типов в стиле constexpr:

template<typename T>
void MyClass::AddType(T value)
{    
    if constexpr (std::is_same<T, bool>::value) {        
        b_val = value;
    } else if constexpr (std::is_same<T, bool>::value) {        
        i_val = value;
    }
}

При компиляции, конструкция целого if уменьшится до b_val = value;, i_val = value; или ничего.

Другой вариант - просто перегружать функцию, просто определяя MyClass::AddType(bool); и MyClass::AddType(int).

. Третий метод - это специализация шаблона . (что лично мне кажется не очень хорошей идеей в данном конкретном случае).

0 голосов
/ 10 октября 2019

Когда компилятор создает специализацию вашей шаблонной функции message.AddType(s);, в его определении (b_val = value;) он сталкивается с недопустимым присваиванием типа, поскольку std::string пытается присвоить bool.

typeid здесь не имеет ничего общего, это мера или RTTI (идентификация типа RunTime), которая является инструментом времени выполнения, и компилятор компилирует код таким, какой он есть (все).

Компиляция не зависит от ветви. if условие не работает как директива условной компиляции #ifdef препроцессора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...