解决模板参数包重载歧义问题

Resolve Template Parameter Pack Overload Ambiguity

提问人:kaisong 提问时间:10/31/2023 最后编辑:Nicol Bolaskaisong 更新时间:10/31/2023 访问量:62

问:

最小示例

我有以下结构和一些专业:

template<size_t ...Tpar>
struct Base{};

struct X{};
struct Y{};

template<typename T, size_t ...Tpar>
struct Spline: Base<Tpar...>{}; // general type

template<typename T>
struct Spline<T>: Base<>{}; // specialization 1

template<typename T, size_t n>
struct Spline<T,n>: Base<n>{}; // specialization 2

template<size_t ...Tpar>
struct Spline<X,Tpar...>: Base<Tpar...>{}; // specialization 3

template<size_t ...Tpar>
struct Spline<Y,Tpar...>: Base<Tpar...>{}; // specialization 4

每个执行机构都很长,至少可以举个例子。

错误

以下歧义出现(类似地为):XY

int main(){
  Spline<X,56> sx56; // error: compiler cannot decide between spec. 2 and spec. 3.
}

演示

为什么超载

我有一个客户类代码,它应该产生各种不同的 bahaviours,具体取决于 i) 主要是类型和 ii) 随后其他模板参数的存在和值。我尝试了不同的东西,这似乎对我正在尝试做的事情很方便——直到现在,我希望重新引入专业 3 和 4。Tpar...

我的期望

我预计会使用专业化 3,因为这是一种类型限制,而只是一个数量专业化。Xn

我想要什么

我想声明,在这种情况下将使用专业化 3。由于 3 和 4 的实现是巨大的,我想在某个地方简明扼要地执行此声明。

解决方法

如果及时修复是强制性的,我会使用以下方法:

template<typename T,size_t ...Tpar>
using Spline = std::conditional_t< std::is_value_t<T,X> , Spline_Spec3<Tpar...> , /*...*/ >;

但那将是

  1. 容易出错
  2. 难以阅读
  3. 需要 X 和 Y 的嵌套 std::conditional_t
  4. 需要重命名专用化类名称
C++ 20 模板专用化 C++-概念 参数包

评论

1赞 HolyBlackCat 10/31/2023
你知道吗?在专用化 (2) 上添加一个条件,以阻止它被用于 和 。requiresXY
0赞 kaisong 10/31/2023
啊,这就是它的用途?(因为我今天尝试了它,因为我当时能够用static_assert实现。这些例子太难理解了。我将深入研究。
1赞 HolyBlackCat 10/31/2023
它只是允许您向模板(或专用化)添加条件,以防止将其用于某些模板参数。A 会给你一个编译错误,但会导致回退到不同的专业化,而这正是你想要的。static_assertrequires
1赞 kaisong 10/31/2023
@HolyBlackCat。很好,确实是我想要的。我目前正在阅读它:)一旦我弄清楚了,我会在这里发布我的尝试:)
0赞 kaisong 10/31/2023
@MarekR。谢谢,:)修复了它

答:

1赞 kaisong 10/31/2023 #1

正如@HolyBlackCat所提议的那样。

#include<iostream>

template<size_t ...Tpar>
struct Base{};

struct X{};
struct Y{};

template<typename T>
concept is_default_floating_point_type = requires(T t){ 
    requires not( std::is_same_v<T,X> or std::is_same_v<T,Y> );
};

template<typename T, size_t ...Tpar>
struct Spline: Base<Tpar...>{}; // general type

template<typename T>
struct Spline<T>: Base<>{}; // specialization 1

template<typename T, size_t n>
    requires is_default_floating_point_type<T>
struct Spline<T,n>: Base<n>{}; // specialization 2

template<size_t ...Tpar>
struct Spline<X,Tpar...>: Base<Tpar...>{
  Spline(){ std::cout << "hi.\n"; }
}; // specialization 3

template<size_t ...Tpar>
struct Spline<Y,Tpar...>: Base<Tpar...>{}; // specialization 4

int main(){
  Spline<X,56> sx56; // now compiler selects specialization 3
}

评论

0赞 HolyBlackCat 11/1/2023
这个概念可以简化为。此外,如果您不介意更笨拙的符号,也可以完全删除该概念:您可以直接在模板中编写条件:.template<typename T> concept is_default_floating_point_type = !(std::is_same_v<T,X> || std::is_same_v<T,Y>);template <typename T, size_t n> requires(!(std::is_same_v<T,X> || std::is_same_v<T,Y>))