成员函数模板特化(在类定义之外定义函数)

问题描述 投票:0回答:1

我一直在 Stack Overflow 上寻找我的问题的解决方案并看到许多类似的主题,但没有指向如此具体案例的答案。

在附带的代码中,一切正常,除非我取消注释

#define ISSUE
。然后我收到很多错误。

这里的目标是只能在类主体中声明专业化。实现需要在类定义后放在同一个文件中。

为什么这不起作用?如何让它发挥作用?

我的编译器支持 C++17,没有更新。

#include <cstdint>
#include <iostream>
#include <type_traits>

// #define ISSUE

template <typename T>
class Test
{
  public:
    template<typename U = T,
        std::enable_if_t<
            std::is_same<T,     bool>::value ||
            std::is_same<T,   int8_t>::value ||
            std::is_same<T,  uint8_t>::value ||
            (std::is_enum<T>::value && (sizeof(T) == 1U))
        ,int> = 0>
    static void special(T data);

#if defined(ISSUE)
    template<typename U = T,
        std::enable_if_t<
            std::is_same<T,  int32_t>::value ||
            std::is_same<T, uint32_t>::value ||
            (std::is_enum<T>::value && (sizeof(T) == 4U))
        ,int> = 0>
    static void special(T data);
#endif    
};

template <typename T>
template <typename, 
        std::enable_if_t<
            std::is_same<T,     bool>::value ||
            std::is_same<T,   int8_t>::value ||
            std::is_same<T,  uint8_t>::value ||
            (std::is_enum<T>::value && (sizeof(T) == 1U))
        ,int>>
void Test<T>::special(T data)
{
    std::cout << "print 8-bit\n";
}

#if defined(ISSUE)
template <typename T>
template <typename, 
        std::enable_if_t<
            std::is_same<T,  int32_t>::value ||
            std::is_same<T, uint32_t>::value ||
            (std::is_enum<T>::value && (sizeof(T) == 4U))
        ,int>>
void Test<T>::special(T data)
{
    std::cout << "print 32-bit\n";
}
#endif    

int main()
{
    Test<uint8_t>{}.special(5);
    Test<int8_t>{}.special(5);
    Test<bool>{}.special(true);
#if defined(ISSUE)
    Test<uint32_t>{}.special(5);
    Test<int32_t>{}.special(5);
#endif    
}

只有帖子:

如何通过专门化在具有单独声明和定义的模板类方法上使用 std::enable_if

有助于获得与

#define ISSUE
一起使用的注释。

c++ templates c++17 typetraits class-template
1个回答
2
投票

为什么这不起作用?

首先,它们只是模板函数重载,而不是成员函数的特化。

SFINAE 只能工作,如果

std::enable_if_t
的条件取决于函数的模板参数类型。这意味着,在您显示的代码中,它必须取决于
U
,而不是类模板参数
T

除此之外,

std::enable_if_t
的第二个参数是函数的返回类型,这将是 SFINAEd。您已提供
int
作为返回值,它必须是
void
(或者不提供,因为它是
std::enable_if_t
的默认类型)。


如何让它发挥作用?

我建议直接在函数签名中使用

std::enable_if_t
作为返回类型的替代方法,而不是在模板参数列表中。

您仍然可以在类之外单独保留函数的定义。


template <typename T>
class Test
{
public:
    template<typename U = T>
    std::enable_if_t<
        std::is_same<U, bool>::value ||
        std::is_same<U, int8_t>::value ||
        std::is_same<U, uint8_t>::value ||
        (std::is_enum<U>::value && (sizeof(U) == 1U))
    > special(T data);

    template<typename U = T>
    std::enable_if_t<
        std::is_same<U, int32_t>::value ||
        std::is_same<U, uint32_t>::value ||
        (std::is_enum<U>::value && (sizeof(U) == 4U))
    > special(T data);
};

查看现场演示 godbolt.org


话虽如此,既然您可以访问 C++17 编译器,请查看

if constexpr
,这是该场景的更好选择。或者使用 fold 表达式 你也可以减少扩展的
std::enable_if
条件,如下所示:

// alias std::enable_if for type checking
template <std::size_t N, typename U, typename... Ts>
using enabled_types = std::enable_if_t<
    (std::is_same_v<U, Ts> || ...) ||
    (std::is_enum_v<U> && (sizeof(U) == N))
 >;

template <typename T>
class Test
{
public:
    template<typename U = T>
    enabled_types<1U, U, bool, int8_t, uint8_t> special(T data);

    template<typename U = T>
    enabled_types<4U, U, int32_t, uint32_t> special(T data);
};

查看现场演示 godbolt.org

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