部分专门化中不能推导模板形参

Template parameters not deducible in partial specialization

本文关键字:形参 不能 专门化      更新时间:2023-10-16

我有一个类似的问题,就像这里发现的一样,但它可能发生,我仍然在做一些不同的事情,所以我还是会问。

有一些类型将被标记为一个标签结构:

template<typename Geometry=void, typename Enable = void>
struct tag 
{
    typedef void type;
};
引入了

、点标记和三角形标记:

struct point_tag {}; 
struct triangle_tag {}; 

使用std::vector:

构造点类型
template<>
struct tag<std::vector<double>>
{
    typedef point_tag type; 
};

和一个三角形类型作为std::array的别名模板:

template<typename Point>
using triangle = 
typename std::enable_if
<
    std::is_base_of<typename tag<Point>::type, point_tag>::value,
    std::array<Point,3>
>::type;
如果作为Point参数传递的参数确实标记为point_tag,则启用

之后,我想用triangle_tag标记所有三角形,像这样:

template <typename Point>
struct tag<triangle<Point>>  
{
    typedef triangle_tag type;
};

std::array是别名的,而不是组合/继承的,因为组合和继承会导致初始化列表构造的问题。但是,编译失败,报错

g++ -std=c++1y main.cpp -o main 
main.cpp:31:8: error: template parameters not deducible in partial specialization:
 struct tag<triangle<Point>>  
        ^
main.cpp:31:8: note:         ‘Point’

如果我不依赖于基于标记的Point参数启用triangle,但对所有类型都这样做:

template<typename Point>
using triangle = 
// This works, but there is no restriction on Point to be tagged with point_tag.
std::array<Point, 3>;

则编译工作正常。然而,然后三角形也是一个三角形,我使用基于类型的任意属性的函数重载来减少那些enable_if失败的函数的函数模板集。我不依赖函数模板的容器接口来确定可行的模板参数,因为有时隐式接口完全相同,但操作语义不同。例如,三角形是封闭的圆形线段(涉及3条边的操作),点链是开放的线段(涉及2条边的操作)。所有操作都需要一个直接访问操作符,这是模板参数的唯一要求,这导致在没有enable_if限制的情况下实现函数模板实例化时产生歧义——所有这些都在链接的文章中讨论。

下面是完整的示例。

我错过了什么吗?如何解决这个问题?

为什么不使用Enable模板参数?
比如:

template <typename Point>
struct tag<
    std::array<Point, 3>,
    typename std::enable_if<
        std::is_base_of<
            typename tag<Point>::type,
            point_tag
        >::value
    >::type
>
{
    typedef triangle_tag type;
};

(好的,你重复enable_if…)

生活例子

这个适合我:

template <typename Point>
struct triangle
{
    static_assert(std::is_same<typename tag<Point>::type, point_tag>::value, "triangle can only contain elements which model a point_tag.");
    Point&       operator[](std::size_t i) { return elems[i]; }
    Point const& operator[](std::size_t i) const { return elems[i]; }    
    Point elems[3];
};