C ++许多SFINAE样式的重载

问题描述 投票:2回答:2

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

#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)
      |          
c++ templates metaprogramming sfinae
2个回答
0
投票

您不能部分专业化模板功能。但是您可以定义具有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
  • 演示

    std::enable_if类重命名为SFINAE,您可以定义一个辅助函数:

    parse

    parse_impl


    0
    投票

    您的问题比模板问题更多是重载问题。

    © www.soinside.com 2019 - 2024. All rights reserved.