C++ 11 : How to write 2 template functions that differ in their return type

标签 c++ c++11 templates type-traits

我想做的是有两个函数模板:一个将字符串转换为 boost::optional<some integer type>以及将字符串转换为 boost::optional<some enum type> 的一个。像这样的事情:

template<typename T> boost::optional<T> func(const std::string &s) { return boost::make_optional(std::stoi(s));}
template<typename T> boost::optional<T> func(const std::string &s) { return boost::make_optional(EnumMapper<T>::map_string_to_enum<T>(s));}

enum Color { Red, Blue, Green};
enum Direction { Up, Down, Left, Right};

auto a = func<int>("1234");
auto b = func<Color>("red");
auto c = func<Direction>("up");

我有一些工作可以为每种枚举类型进行专门化:

template<> boost::optional<Color> func(const std::string &s) { return boost::make_optional(EnumMapper<Color>::map_string_to_enum<Color>(s));}
template<> boost::optional<Direction> func(const std::string &s) { return boost::make_optional(EnumMapper<Direction>::map_string_to_enum<Direction>(s));}

但是对于几十个枚举来说,这看起来很丑陋并且容易出错。我有一种感觉,这就是类型特征的用途,但我发现的示例似乎都不适合我想做的事情。

编辑:感谢宋元耀!这有效:

#include <iostream>
#include <type_traits>
#include <string>
#include <boost/optional.hpp>
#include <cstdint>

enum Color {
    Red,
    Green,
    Blue
};

enum Direction {
    Up,
    Down,
    Left,
    Right
};

template <typename T> struct EnumMapper { static boost::optional<T> map_string_to_enum(const std::string &s) = delete; };

template <> boost::optional<Color> EnumMapper<Color>::map_string_to_enum(const std::string &s) {
    return Color::Green;
}

template <> boost::optional<Direction> EnumMapper<Direction>::map_string_to_enum(const std::string &s) {
    return Direction::Right;
}

template<typename T>
typename std::enable_if<std::is_enum<T>::value, boost::optional<T>>::type
func(const std::string &s) { 
    return EnumMapper<T>::map_string_to_enum(s);
}

template<typename T>
typename std::enable_if<std::is_integral<T>::value, boost::optional<T>>::type
func(const std::string &s) { 
    return boost::make_optional<T>(std::stoi(s));
}

int
main() {
    auto a = func<std::uint8_t>("123");
    std::cout << static_cast<int>(*a) << std::endl;
    auto b = func<Color>("Red");
    std::cout << static_cast<int>(*b) << std::endl;
    auto c = func<Direction>("Up");
    std::cout << static_cast<int>(*c) << std::endl;
    auto d = func<std::uint32_t>("2345");
    std::cout << static_cast<int>(*d) << std::endl;
}

最佳答案

您可以使用类型特征 std::is_enum,并应用 SFINAE .

template<typename T>
typename std::enable_if<std::is_enum<T>::value, boost::optional<T>>::type
func(const std::string &s) { 
    return boost::make_optional(EnumMapper<T>::map_string_to_enum<T>(s));
}

请注意,您还必须限制第一个重载的类型。您可以检查它是否为int,或使用std::is_integral。例如

template<typename T>
typename std::enable_if<std::is_same<T, int>::value, boost::optional<T>>::type
func(const std::string &s) { 
    return boost::make_optional(std::stoi(s));
}

关于C++ 11 : How to write 2 template functions that differ in their return type,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62910702/

相关文章:

c++ - 生成随机数但要求有一定数量

c++ - 关于掉期执行的问题

c++ - 使用 qmake/Qt Creator 与调试/发布库链接

c++11 - 抑制警告:deleting 'void*' is undefined

c++ - 为什么具有私有(private)构造函数的类不阻止从此类继承?如何控制哪些类可以从某个基类继承?

c++ - 使用 std::function 保证没有动态内存的最小语法

c++ - 静态嵌套 bool 会帮助我禁用对某些类型的调用还是有更简洁的方法?

c++ - 如何在非类型模板类的专门化声明之外定义方法?

c++ - 替换 std::map 中的键

json - 对一个 JSON 模板进行多项更改