[Reopened] Why does this error even exist?

Pages: 12
> I should have specified, the return type for f() in my example should be ignored
> it does change in each class but it is not the same as the class it is in.

So what is so different? The result types have to be covariant no matter what that second hierarchy is. As long as that is the case, the structure of the solution would be the same.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
template < typename DERIVED, typename RESULT_HOLDER, typename... BASE > struct crtp_helper ;

template < typename T, typename RESULT_HOLDER > struct crtp_helper<T, RESULT_HOLDER> { /* ... */ };

struct one { virtual ~one() = default ; };

struct base : crtp_helper< base, one >
{
    using result_type = one ;
    virtual ~base() = default ;
    const result_type& get() const { return do_get() ; }
    protected: virtual const result_type& do_get() const = 0 ;
};

template < typename T > struct result_is { using type = T ; }; // documentation helper

template < typename DERIVED, typename RESULT_HOLDER, typename FIRST, typename... REST >
struct crtp_helper< DERIVED, RESULT_HOLDER, FIRST, REST... > : virtual FIRST, virtual REST...
{
    using result_type = typename RESULT_HOLDER::type ;
    const result_type& get() const { return dynamic_cast< const result_type& >( do_get() ) ; }
    protected: virtual const result_type& do_get() const override = 0 ;
    // ...
};

struct two : virtual one {}; struct three : virtual two {}; struct four : virtual three {}; struct five : virtual four {};

struct A : crtp_helper< A, result_is<two>, base > {};
struct B : crtp_helper< B, result_is<three>, base > {};
struct C : crtp_helper< C, result_is<four>, base > {};
struct ABC : crtp_helper< ABC, result_is<five>, A,B,C > {};

template < typename T > struct canned_impl : T
{
    using result_type = typename T::result_type ;
    protected: virtual const result_type& do_get() const override
    { static result_type result ; return result ; }
};

int main()
{
    canned_impl<B> b ; const B::result_type& rb = b.get() ;
    canned_impl<ABC> abc ; const ABC::result_type& rabc = abc.get() ;
}

http://coliru.stacked-crooked.com/a/73d5fac15fd260ea
f() is just one of many virtual functions following many completely different inheritance hierarchies, and then there are other virtual functions which are just normal virtual functions. The classes that extend crtp_helper need to be [i]the actual classes[/tt]. With your solutions, the number of classes necessary is overkill, and makes some things impossible for me. I'm sorry for not explaining more thoroughly but my project is still very much in the planning stage and I don't have much to show except for what's in my head.

Is there no way to simplify my solution? It works for my scenario despite being somewhat cumbersome.

I do really appreciate your awesome help by the way, I'm just not good at making the clear what I am trying to do. I've never been good at explaining things, and in this case I don't even have code I can point at.
OK, so I found a solution I am happy with (thanks JLBorges!)
http://coliru.stacked-crooked.com/a/a36a08248ba01948
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
template<typename DerivedT, typename... ParentT>
struct Middle;
template<typename DerivedT, template<typename...> class InheriterT, typename... ParentT>
struct Middle<DerivedT, InheriterT<ParentT...>>
: InheriterT<ParentT...>
{
    void test()
    {
        std::cout << "it works" << std::endl;
    }
};
template<typename... Args>
struct DefaultInheriter
: virtual Args...
{
};
template<typename DerivedT, typename... ParentT>
struct Middle
: Middle<DerivedT, DefaultInheriter<ParentT...>>
{
};
44
45
46
47
48
49
50
51
52
53
54
template<typename... Args>
struct ABInheriter
: virtual Args...
{
    virtual ABInheriter *f() const override = 0;
};
struct Derived
: Middle<Derived, ABInheriter<A, B>>
{
    virtual Derived *f() const override = 0;
};
The specialization is where the implementation goes, and the original just uses the specialization. The user can use the template normally except in cases where there would be a conflict from the 'more than one file overrider' error.
Last edited on
Upon more investigation of the original example in the first post, I'm pretty sure there should be no reason for the error to occur if Middle is an abstract class. I am fully convinced it's an oversight in the standard. Oh well.
Topic archived. No new replies allowed.
Pages: 12