【问题标题】:Can I tell the C++ compiler how to do arbitrary type conversions itself?我可以告诉 C++ 编译器如何自己进行任意类型转换吗?
【发布时间】:2020-03-24 09:47:42
【问题描述】:

这个问题是另一个问题的后续问题:How to realize automatic type conversion for template methods?

如果在模板方法中需要进行类型转换,我可以告诉编译器如何自己进行转换吗?

我知道编码转换的两种可能性:

  • 模板专业化
  • 提供转换重载(这是前一个问题的答案)。

两者都很好,但可能需要编写样板代码。有没有办法只“注入”类型转换代码,让编译器完成剩下的工作?

请参阅以下示例代码。我需要提供从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;
}

【问题讨论】:

  • “编写样板代码”。大部分情况下都是正确的,因为您在错误的级别上做了:void storeSetting(const std::string&amp; s) { storeSetting(Setting(stoi(s))); }。甚至是 makeSetting 重载集。
  • @Jarod42 这是创建最小示例的缺点。 ;) 在我的实际代码中,storeSetting 的对应部分也是无法修改的第三方库的一部分(它是类成员函数)。我会修改我的问题...
  • @Jarod42 当然,就原始示例代码而言,您的评论是完全正确的......我意识到我对可能的解决方案施加了许多限制。可能没有……有吗?
  • 您始终可以将所有对storeSetting 的调用替换为对myStoreSetting 的调用,并让您的包装器重载以处理转换。
  • 风格问题,avoid specializing function templates。在这里可以进行专业化的事实只不过是对技术的好奇。对于现实世界的代码,您几乎肯定会想专门使用重载。

标签: c++ templates type-conversion


【解决方案1】:

你不能在你不拥有的类型之间添加隐式转换。

但您仍然可以创建为您进行转换的函数:

// 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)};
}

然后在你的通用函数中:

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));
    }
}

【讨论】:

    猜你喜欢
    • 2023-03-10
    • 1970-01-01
    • 2014-11-11
    • 1970-01-01
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-28
    相关资源
    最近更新 更多