Могу ли я сказать компилятору C ++, как выполнять произвольные преобразования типов? - PullRequest
1 голос
/ 24 марта 2020

Этот вопрос является продолжением другого вопроса: Как реализовать автоматическое c преобразование типов для шаблонных методов? .

Если в шаблонном методе необходимо преобразование типов Могу ли я как-то указать компилятору, как выполнить только это преобразование?

Я знаю две возможности кодирования преобразования:

  • специализация шаблона
  • , обеспечивающая преобразование перегрузка (которая была ответом на предыдущий вопрос).

Оба в порядке, но могут потребовать написания стандартного кода. Есть ли способ «внедрить» только код преобразования типа и позволить компилятору сделать все остальное?

Пожалуйста, посмотрите следующий пример кода. Мне нужно предоставить преобразование из std::string в мой Setting класс. Как я мог сказать компилятору, как его преобразовать?

#include <string>
#include <vector>

class Setting
{
public:

    Setting(int)
    {
    }

    Setting(double)
    {
    }

    // It is not possible to provide a constructor taking std::string as argument,
    // because this code is within an external libary!!!
};

// Is is not possible to create an overload of this method, since in real life
// it is a class member function within an external library.
//
void storeSetting(const Setting&)
{
    // Storing setting...
}

// Template method that works with int, double and float, because Settings can
// be created from these basic types. But the method will not work
// for std::string, since there is no appropriate constructor.
template <typename Type>
void storeAll(std::vector<Type> elements)
{
    // A lot of lengthy storage preparation code
    // ...
    //

    // Final Storage
    for (const Type& element : elements)
    {
        storeSetting(element);
    }
}

// Solution by template specialization
template <>
void storeAll(std::vector<std::string> elements)
{
    // A lot of lengthy storage preparation code
    // ...
    //

    // Final Storage
    for (const std::string& element : elements)
    {
        storeSetting(stoi(element));
    }
}

// Solution by providing a conversion overload
//
// TODO: When containers are concerned, this is not handy.
// I dont have to repeat the "lengthy storage preparation code".
// On the other hand, the conversion code is lengthy boilerplate code itself.
// Is there another way to "inject" a user-defined type conversion?
void storeAll(std::vector<std::string> elements)
{
    std::vector<int> convertedElements;

    for (const std::string& element : elements)
    {
        convertedElements.push_back(stoi(element));
    }

    storeAll(convertedElements);
}

int main()
{
    std::vector<double> numbers1 = {1.0, 2.0, 3.0};
    std::vector<int> numbers2 = {2, 3, 4};
    std::vector<float> numbers3 = {3.0, 4.0, 5.0};

    storeAll(numbers1);
    storeAll(numbers2);
    storeAll(numbers3);

    std::vector<std::string> numbers4 = {"4", "5", "6"};
    storeAll(numbers4);

    return 0;
}

1 Ответ

2 голосов
/ 24 марта 2020

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

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

// The forwarding one for exisiting contructor
template <typename ... Ts>
auto makeSetting(const Ts&... args)
-> decltype(Setting{args...})
{
    return Setting{args...};
}

// Optionally, one to avoid unwanted copy constructor
const Setting& makeSetting(const Setting& s) { return s; }

// Your extra version
Setting makeSetting(const std::string& s)
{
    return Setting{std::stoi(s)};
}

Затем в вашем обобщенном c функция:

template <typename T>
void storeAll(std::vector<T> elements)
{
    // A lot of lengthy storage preparation code
    // ...

    // Final Storage
    for (const auto& element : elements)
    {
        storeSetting(makeSetting(element));
    }
}
...