2017-01-09 12 views
20

Я ссылался на http://en.cppreference.com/w/cpp/language/typeid, чтобы написать код, который делает разные вещи для разных типов.Тип id std :: string для переменной vs. string в аргументе?

Код указан ниже, и пояснения приводятся в комментариях.

#include <iostream> 
#include <typeinfo> 

using namespace std; 

template <typename T> 
void test_template(const T &t) 
{ 
    if (typeid(t) == typeid(double)) 
     cout <<"double\n"; 
    if (typeid(t) == typeid(string)) 
     cout <<"string\n"; 
    if (typeid(t) == typeid(int)) 
     cout <<"int\n"; 
} 

int main() 
{ 
    auto a = -1; 
    string str = "ok"; 
    test_template(a); // Prints int 
    test_template("Helloworld"); // Does not print string 
    test_template(str); // Prints string 
    test_template(10.00); // Prints double 

    return 0; 
} 

Почему test_template(str) печать "строка", а test_template("Helloworld") не?

Кстати, моя г ++ версии г ++ (Ubuntu 5.4.0-6ubuntu1 ~ 16.04.4) 5.4.0 20160609.

+17

Почему downvotes? Конечно, это на базовом уровне, но вопрос завершен, понятен, и OP даже включает версию компилятора! – TartanLlama

+3

'' Helloworld ''не является' std :: string'. Но '' Helloworld '' был бы. – Jarod42

+2

@TartanLlama: Я бы предположил, что это из-за пользователя, который хочет использовать 'typeid' для написания ужасно хрупкого кода. –

ответ

22

В этом вызове

test_template("Helloworld"); // Does not print string 

Аргумент "Helloworld" строковый литерал, который имеет тип const char[11].

Поскольку параметр функции представляет собой тип ссылки

void test_template(const T &t) 
          ^^^ 

затем внутри функции аргумент (точнее параметр) имеет тип const char (&t)[11].

Строковые литералы в C++ имеют типы постоянных массивов символов с числом элементов, равным количеству символов в строковом литерале плюс нулевой конец.

В этом вызове

test_template(str); 

аргумент имеет тип std::string, так как переменная str объявляется как

string str = "ok"; 
^^^^^^ 

Он был инициализирован строкой буквальным "ok" тем не менее, сам объект относится к типу std::string ,

+1

Должен ли 'conat char' быть' const char'? (Я не могу отправить изменения только с одним изменением.) –

+0

@ChristopheStrobbe Что значит? –

+0

Ну, 'conat' в' conat char (& t) [11] 'в вашем ответе. –

9

Строковые литералы как "Helloworld" являются постоянные массивы символов.

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


Как побочная заметка, использование такой функции, как ваш, считается запахом кода и плохим дизайном. Используйте перегруженные функции вместо разных аргументов. Это также решит вашу проблему со строками.

+3

Согласен, здесь нет никакого смысла иметь шаблон. Нет общих функций. – AndyG

+1

Спасибо! Вместо этого я рассмотрю использование перегруженных функций. – Meehatpa

16

Строковые литералы в C++ имеют тип const char[N+1], где N - количество символов в строке. std::string - это стандартный класс библиотеки, который владеет строкой и выполняет несколько операций над ней. A std::string можно построить из const char[N], но это не одно и то же.