常量和非常量类型的相同模板专用化

Same template specialization for const & non const type

本文关键字:常量 专用 非常 类型      更新时间:2023-10-16

我有以下代码:

#include <iostream>
class A
{};
class B
{};
template<typename T>
void Do(T data)
{
std::cout << "Do() defaultn";
}
template<>
void Do(A* data)
{
std::cout << "Do(A*)n";
}
template<>
void Do(B* data)
{
std::cout << "Do(B*)n";
}
int main(int argc, char* argv[])
{
A* a = nullptr;
B* b = nullptr;
const A* aConst = nullptr;
const B* bConst = nullptr;
Do(a);
Do(aConst);
Do(b);
Do(bConst);
return 0;
}

输出:

Do(A*)
Do() default
Do(B*)
Do() default

我应该如何重写代码以共享const&非const类型,无需复制粘贴带有const关键字说明符的专业化,从而生成输出:

Do(A*)
Do(A*)
Do(B*)
Do(B*)

您可以重载,而不是专门化。使用

template<typename T, std::enable_if_t<std::is_same_v<std::decay_t<T>, A>, bool> = true>
void Do(T* data)
{
std::cout << "Do(A*)n";
}
template<typename T, std::enable_if_t<std::is_same_v<std::decay_t<T>, B>, bool> = true>
void Do(T* data)
{
std::cout << "Do(B*)n";
}

传递const A*/A*/const B*/B*时将调用这些函数,因为它们比通用模板更匹配。它们是更好匹配的原因是T更受约束。它被认为是更专业的,因此它将在过载解决中与通用模板的平局中获胜。

C++14

我对这个答案投了赞成票,这对SFINAE来说是一个很好的展示。要对其进行扩展,可以使用std::is_convertible简化SFINAE表达式。这更类似于重载解析的工作方式(添加const限定符(。

template<typename T, std::enable_if_t<std::is_convertible_v<T*, const A*>, int> = 0>
void Do(T* data)
{
std::cout << "Do(A*)n";
}
template<typename T, std::enable_if_t<std::is_convertible_v<T*, const B*>, int> = 0>
void Do(T* data)
{
std::cout << "Do(B*)n";
}

C++17

另外,在带有constexpr if的C++17中,您可以在所有情况下使用一个函数:

template<typename T>
void Do(T data)
{
if constexpr (std::is_convertible_v<T, const A*>)
std::cout << "Do(A*)n";
else if constexpr (std::is_convertible_v<T, const B*>)
std::cout << "Do(B*)n";
else    
std::cout << "Do() defaultn";
}

如果你愿意写一个小存根,你可以使用这个模式:

template<>
void Do(const A* data)
{
std::cout << "Do(A*)n";
}
template<>
void Do(A* data)
{
Do((const A*)data);
}

您不想复制的主代码使用const A*,因为您希望它也能处理常量数据。非常简单地转发给它。