2

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?

Community
  • 1
  • 1
tmaric
  • 5,347
  • 4
  • 42
  • 75
  • 3
    Your problem is similar to your link. Why not use your template `Enable` (`template struct tag, typename std::enable_if ::type, point_tag>::value>::type`) ? – Jarod42 Jul 25 '14 at 12:07
  • 1
    SFINAE being cool and all... it is a complicated beast that I don't think is appropriate to your problem. Do you want to provide a different version of `triangle` if the element is not `point_tag`? This looks closer to `static_assert` (i.e. hard failure if the type is not a point). – David Rodríguez - dribeas Jul 25 '14 at 13:26
  • yes, I need different versions, like a different version of polyhedron when the element is not tagged with a polygon_tag, but a graph_polygon_tag. right now, I have all this up and running, the only thing missing is using initializer lists with array-based concepts. that's why I want to alias the array + tag it. I still don't get the first comment.. what should I do? – tmaric Jul 25 '14 at 13:29
  • I`m not sure I understand your comment on line 27 at http://coliru.stacked-crooked.com/a/b5d5c4b45c5442c3 about "// This works, but there is no restriction on Point to be tagged with point_tag." I understand that restriction is exactly what you impose by that SFINAE, and if you comment out lines 30-34 that compiles like a charm http://coliru.stacked-crooked.com/a/a1b52a645001d259 – Solkar Jul 25 '14 at 13:36
  • @Solkar: you have commented out the partial specialization of `tag`, which is then used to enable function templates that take `triangle` as arguments... the goal is to tag the triangle, just like the point is taged. then you have a set of function templates that are enabled based on tags (see the article I've linked). tags reduce the set of function templates using SFINAE, so you don't need to implement algorithms as partially specialized structs or do value based tag dispatching and end up with function templates that have 4 arguments 2 real, and 2 tags. – tmaric Jul 25 '14 at 13:41
  • @tmaric. I know what tags are good for. I'm confused about your comment on line 27; that comment is not about tagging triangles but tagging ->Points<-. – Solkar Jul 25 '14 at 13:50
  • @Solkar: if you uncomment `std::array;` you have to comment out the code up to (excluding) line 21, which means that any array taking any template argument (here named Point) is a triangle, which is not true. An array of 3 strings is not a triangle. There is no restriction on points if this is done.. sorry if I'm not clear enough.. – tmaric Jul 27 '14 at 11:48
  • So instead of you correcting (or just deleting) that comment I "have to" do sth about your code? No, I don't.... – Solkar Jul 27 '14 at 12:09
  • @Solkar: You have completely misunderstood what I wrote. I will try to rephrase: to turn on line 28, *one would have to comment out lines 22-26*. Not you personally. thanks for the -1. – tmaric Jul 27 '14 at 12:24
  • @Solkar: Also, why would I delete/correct a valid comment? The comment states that the line below works, but doesn't restrict Point in array to really be a tagged point. So you deal away -1's for not understanding comments? (applause). – tmaric Jul 27 '14 at 12:26
  • I granted you this -1 because you're not cooperating on improving your questions quality. – Solkar Jul 27 '14 at 12:41
  • @Solkar: whatever, I will not argue with you here. I will however suggest that you read about question quality on SO. I did my research and presented short working examples. – tmaric Jul 27 '14 at 12:41
  • No, not "whatever". It's your programming problem you want to have solved here by other people's efforts, thus it's your obligation to cooperate. – Solkar Jul 27 '14 at 12:47
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/58100/discussion-between-tmaric-and-solkar). – tmaric Jul 27 '14 at 13:15

2 Answers2

1

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];
};
Brandon Kohn
  • 1,612
  • 8
  • 18
1

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

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • 1
    So the key trick was not to use the `triangle` to specialize `tag`, but `std::array`, and enable the `tag` specialization based on the same condition on which `triangle` is defined. I can put this in a macro, if I stick with this option, I'll accept your answer. Thanks! – tmaric Jul 27 '14 at 11:45