简体   繁体   中英

Template parameters not deducible in partial specialization

I have a similar issue like the one found here but it might happen that I am still doing something different, so I will ask none-the less.

There are some types that will be tagged with a tag structure:

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

and point and triangle tags are introduced:

struct point_tag {}; 
struct triangle_tag {}; 

to construct the point type using the std::vector :

template<>
struct tag<std::vector<double>>
{
    typedef point_tag type; 
};

and a triangle type as an alias template of the 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;

that is enabled if the argument passed as Point parameter is really tagged with point_tag ,

and afterwards, I would like to tag all triangles with the triangle_tag like this:

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

The std::array is aliased and not composited/inherited because composition and inheritance causes problems with the initializer list construction . However, the compililation fails with the error

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’

If I don't rely on enabling the triangle based on the Point parameter being tagged, but do it for all types like this:

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

then the compilation works fine. However, then triangle is also a triangle , and I am using function overloading based on arbitrary properties of types to reduce the function template set from those functions for which the enable_if fails. I am not relying on container interfaces for function templates to determine the viable template arguments because sometimes the implicit interfaces are exactly the same , but the operation semantics is different. For example, a triangle is a closed circular line segment (involves operation on 3 edges), and a point chain is an open-ended line segment (involves operations on 2 edges). All operations require a direct access operator which is the only requirement for the template parameter, which leads to ambiguity in function template instantiation when they are implemented without enable_if restrictions - all covered in the linked article.

Here is the complete example .

Is there something I'm missing? How to get around this issue?

This works for me:

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];
};

What not use your Enable template parameter ?
Something like:

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;
};

(ok, you repeat the enable_if ...)

Live example

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM