c++ - C++许多SFINAE样式的重载

标签 c++ templates metaprogramming sfinae

是否可以一次多次进行许多重载/指定,如下面的代码所示。
我希望很清楚,我正在尝试实现什么,但是编译器并不这么认为。

#include <stdint.h>

struct IP_address
{
    uint32_t value;
};


template<typename T> struct Unsigned_type {};
template<> struct Unsigned_type<uint8_t >{ typedef uint8_t   type; };
template<> struct Unsigned_type<uint16_t>{ typedef uint16_t  type; };
template<> struct Unsigned_type<uint32_t>{ typedef uint32_t  type; };
template<> struct Unsigned_type<uint64_t>{ typedef uint64_t  type; };

template<typename T> struct Signed_type {};
template<> struct Signed_type<uint8_t >{ typedef uint8_t   type; };
template<> struct Signed_type<uint16_t>{ typedef uint16_t  type; };
template<> struct Signed_type<uint32_t>{ typedef uint32_t  type; };
template<> struct Signed_type<uint64_t>{ typedef uint64_t  type; };

template<typename T> 
T parse(const char*);

template <typename T>
typename Unsigned_type<T>::type parse(const char* str)
{
    return 1;
}

template <typename T>
typename Signed_type<T>::type parse(const char* str)
{
    return -1;
}

template <>
IP_address parse(const char* str)
{
    IP_address result;
    result.value = 0x08080808;
    return result;
}


int main()
{
    uint32_t parsed_uint = parse<uint32_t>("300");
    int32_t parsed_int = parse<int32_t>("-1337");
    IP_address parsed_ip = parse<IP_address>("8.8.8.8");
    uint8_t should_throw = parse<uint8_t>("300");
    return 0;
}


clang和gcc都告诉call to 'parse' is ambiguous,但是我不知道为什么,我已经明确指定了类型!请帮助我了解为什么它不能编译以及如何使其工作?顺便说一句,在这种情况下甚至可以不使用宏就不重复自己吗?

根据要求编译错误。
test.cpp: In function ‘int main()’:
test.cpp:47:49: error: call of overloaded ‘parse<uint32_t>(const char [4])’ is ambiguous
   47 |     uint32_t parsed_uint = parse<uint32_t>("300");
      |                                                 ^
test.cpp:22:3: note: candidate: ‘T parse(const char*) [with T = unsigned int]’
   22 | T parse(const char*);
      |   ^~~~~
test.cpp:25:33: note: candidate: ‘typename Unsigned_type<T>::type parse(const char*) [with T = unsigned int; typename Unsigned_type<T>::type = unsigned int]’
   25 | typename Unsigned_type<T>::type parse(const char* str)
      |                                 ^~~~~
test.cpp:31:31: note: candidate: ‘typename Signed_type<T>::type parse(const char*) [with T = unsigned int; typename Signed_type<T>::type = unsigned int]’
   31 | typename Signed_type<T>::type parse(const char* str)
      |                               ^~~~~
test.cpp:50:48: error: call of overloaded ‘parse<uint8_t>(const char [4])’ is ambiguous
   50 |     uint8_t should_throw = parse<uint8_t>("300");
      |                                                ^
test.cpp:22:3: note: candidate: ‘T parse(const char*) [with T = unsigned char]’
   22 | T parse(const char*);
      |   ^~~~~
test.cpp:25:33: note: candidate: ‘typename Unsigned_type<T>::type parse(const char*) [with T = unsigned char; typename Unsigned_type<T>::type = unsigned char]’
   25 | typename Unsigned_type<T>::type parse(const char* str)
      |                                 ^~~~~
test.cpp:31:31: note: candidate: ‘typename Signed_type<T>::type parse(const char*) [with T = unsigned char; typename Signed_type<T>::type = unsigned char]’
   31 | typename Signed_type<T>::type parse(const char* str)
      |          

最佳答案

您不能部分专门化模板功能。但是您可以定义一个具有SFINAE调用运算符的类模板:

#include <type_traits>

template<typename T>
struct parse
{
    template<class U = T>
    std::enable_if_t<std::is_signed_v<U>, T> operator()(const char* str)
    {
        return -1;
    }

    template<class U = T>
    std::enable_if_t<!std::is_signed_v<U>, T> operator()(const char* str)
    {
        return 1;
    }
};

parse<T>明确专用时,将进行模板参数替换。如果T是,例如unsignedstd::is_signed_v<T>将是false。这使编译器尝试对格式错误的std::enable_if_t<false, T>进行专门化处理。值得庆幸的是,这发生在SFINAE的范围内:该定义被简单地忽略了,从而获得了未签名的版本。

一点文件
  • std::is_signed
  • std::enable_if
  • SFINAE

  • 演示版

    parse类重命名为parse_impl,您可以定义一个辅助函数:
    template<class T>
    auto parse(const char* arg)
    { return parse_impl<T>{}(arg); }
    

    Full program

    关于c++ - C++许多SFINAE样式的重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60001989/

    相关文章:

    C++ 多参数模板化类成员特化

    c++ - 如何分配子类的方法成员指针?

    Ruby 元编程问题

    c++ - 错误 C2079 : 'X::x' uses undefined struct 'T'

    c++ - rand_r 不在范围内,gcc mingw 在 Windows 上的 cygwin 下

    c++ - std::vector<char> 到 std::string

    javascript - 在 emberjs 中动态创建模型时检测事件

    python - 元类在现实世界中的良好用途(例如在 Python 中)

    c++ - C++ 如何处理递归类定义?

    c++ - 是否可以在 C++ 中使用不同行大小的矩阵?