Преобразование типов в создании шаблона класса - PullRequest
0 голосов
/ 09 сентября 2018

У меня есть шаблон класса item, в котором хранятся объекты различных типов T. Он также присоединяет атрибуты к этим объектам в процессе создания / инициализации.

Одна особая вещь, которую я хочу достичь, это то, что всякий раз, когда item видит const char *, он считает и сохраняет его как std::string. Это можно сделать следующим образом.

Но при проверке типов я обнаружил, что экземпляр item, созданный из const char *, по-прежнему отличается по типу от item, созданный из std::string. Пожалуйста, смотрите последнюю строку с комментарием false, который я хочу сделать true.

#include <iostream>
#include <string>
#include <type_traits>

using namespace std;

template<typename T>
using bar = typename std::conditional<std::is_same<T, const char *>::value,
                                      string, T>::type;

template<typename T>
class item
{
    bar<T> thing;

    // other attributes ...

public:
    item(T t) : thing(t) {}

    // other constructors ...

    bar<T> what() const
    {
        return thing;
    }
};

int main()
{
    auto a = item("const char *");     // class template argument deduction (C++17)
    auto b = item(string("string"));   // class template argument deduction (C++17)

    cout << std::boolalpha;
    cout << (typeid(a.what()) == typeid(b.what())) << endl; // true
    cout << (typeid(a) == typeid(b)) << endl;               // false
}

Мой вопрос: возможно ли внести какие-либо изменения в класс шаблона item, чтобы item, созданный из const char *, стал таким же по типу, как item, созданный из std::string

Другими словами, могу ли я внести какие-либо изменения в дизайн класса шаблона item, чтобы typeid(a) == typeid(b) получил значение true?

Спасибо!

Примечание. Далее следует предыдущий вопрос о функции шаблона. Но я думаю, что есть нечто принципиально иное, что оно заслуживает отдельного вопроса.

Редактировать: Моя цель - изменить дизайн класса шаблона item (например, item подписей), а не кода в main, который предполагается предоставлять пользователям. Я хочу упростить жизнь пользователям item, не прося их явно указывать тип T в экземплярах. Это должно быть сделано путем дедукции аргумента класса шаблона C ++ 17 или некоторых эквивалентных обходных путей.

Обновление: спасибо всем! Особая благодарность @xskxzr, чья однострочник точно решает мой вопрос. С определяемыми пользователем руководствами по выводу для вывода аргументов шаблона класса, мне даже не нужна техника bar<T> в моем предыдущем коде. Я поместил обновленный код ниже для вашего сравнения.

#include <iostream>
#include <string>

using namespace std;

template<typename T>
class item
{
    // UPDATE: no bar<T> needed any more
    T thing;

    // other attributes ...

public:
    item(T t) : thing(t) {}

    // other constructors ...

    // UPDATE: no bar<T> needed any more
    T what() const
    {
        return thing;
    }
};

item(const char *) -> item<std::string>;  // UPDATE: user-defined deduction guide !

int main()
{
    auto a = item("const char *");     // class template argument deduction (C++17)
    auto b = item(string("string"));   // class template argument deduction (C++17)

    cout << std::boolalpha;
    cout << (typeid(a.what()) == typeid(b.what())) << endl; // true
    cout << (typeid(a) == typeid(b)) << endl;               // UPDATE: now true !
}

Ответы [ 4 ]

0 голосов
/ 09 сентября 2018

Вы можете добавить определяемое пользователем руководство по удержанию :

item(const char *) -> item<std::string>;

С этим руководством по выводу, a будет выведено как item<std::string>.

0 голосов
/ 09 сентября 2018

Хорошо, я никогда раньше не видел и не использовал std :: conditional, поэтому я не был уверен, что он делает, но, прочитав его и поиграв с вашим кодом, я заставил его работать, используя

bar<T>

как тип шаблона. Так что вместо

auto a = item<const char*>("const char *");
auto b = item<string>(string("string"));

Я сделал

auto a = item<bar<const char*>>("const char *");
auto b = item<bar<string>>(string("string"));

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

auto c = item<bar<int>>(5);

Не уверен, что это хорошее решение (именно поэтому я сказал "работа"), но посмотрите на мой другой ответ о том, что типы классов на самом деле разные.

0 голосов
/ 09 сентября 2018

Нет, вы не можете напрямую сделать typeid двух шаблонных объектов, использующих разные аргументы шаблона, одинаковыми.

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

template<typename T, typename R = T>
item<R> make_item(T&& t)
{
    return item<T>(std::forward<T>(t));
}

// Specialization for const char *
template<>
item<std::string> make_item(const char *&& str)
{
    return item<std::string>(str);
} 

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

0 голосов
/ 09 сентября 2018

Это скорее предположение, чем ответ, но я бы сказал нет. Шаблоны раскрываются во время компиляции, так как вы создаете

item<const char*>

и

item<std::string>

тогда расширяемый код выглядит как

class item1
{
    bar<const char*> thing;

    // other attributes ...

public:
    item(const char* t) : thing(t) {}

    // other constructors ...

    bar<const char*> what() const
    {
        return thing;
    }
};


class item2
{
    bar<std::string> thing;

    // other attributes ...

public:
    item(std::string t) : thing(t) {}

    // other constructors ...

    bar<std::string> what() const
    {
        return thing;
    }
};

(более или менее; на самом деле их не назовут item1 и item2)

Как вы решили оценивать эти два типа, зависит от вас, но для компилятора это фактически два разных типа.

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