0

I have two interfaces that I want to use with CRTP for static polymorphism. One of them contains a function whose types in the signature are implementation-dependent.

This problem looks like what has been asked here without solution. The solution I came up with includes an additional templated structure defining the type. This template is then specialized for the implementation avoiding the "invalid use of incomplete type" error.

Here my code

#include <iostream>
#include <memory>

template<class impl1>
struct Interface1 {
    double foo() { return static_cast<impl1*>(this)->fooimpl();}
};

template<class impl1, class impl2>
struct typeHelp;

template<class impl1, class impl2>
struct Interface2 {
    void bar(typename typeHelp<impl1,impl2>::type value) {
        static_cast<impl2*>(this)->barimpl(value);
    }
};

//Implementation2 pre declaration
template<class impl1>
struct Implementation2;

//Partial specialization of templated typeHelp
template<class impl1>
struct typeHelp<impl1, Implementation2<impl1>> {
    using type = int;
};

//Implementation2
template<class impl1>
struct Implementation2 : public Interface2<impl1, Implementation2<impl1>> {
    std::shared_ptr<Interface1<impl1>> imp1;
    void barimpl(typename typeHelp<impl1,Implementation2>::type value) {
        std::cout << imp1->foo() << " " << value << std::endl;
    }
};

//Implementation1
struct Implementation1 : public Interface1<Implementation1> {
    double fooimpl() {return 0.;}
};

int main()
{
    Implementation2<Implementation1> obj;
    obj.imp1 = std::make_shared<Implementation1>();
    obj.bar(4);
}

What I don't like in this code is that Interface2 and typeHelp depend on template parameter impl1. This works for my particular case, where Implementation2 is templated with respect to impl1 but it wouldn't if Implementation2 weren't. I wonder if there is a more general and elegant solution to this problem.

Teloze
  • 279
  • 2
  • 8

1 Answers1

0

My bad; a little bit more of search and I would have found the answer. On this link, Andy G points out that it is possible to specialize a class template with a templated class. The result is more clean than before

#include <iostream>
#include <memory>

//Interface1.hpp
template<class impl1>
struct Interface1 {
    double foo() { return static_cast<impl1*>(this)->fooimpl();}
};

//Interface2.hpp
template<class impl2>
struct typeHelp;

template<class impl2>
struct Interface2 {
    void bar(typename typeHelp<impl2>::type value) {
        static_cast<impl2*>(this)->barimpl(value);
    }
};

//Implementation2.hpp
template<class impl1>
struct Implementation2;

//specialization of typeHelp with templated class
template<class impl1>
struct typeHelp<Implementation2<impl1>> {
    using type = int;
};

//Actual implementation of Implementation2
template<class impl1>
struct Implementation2 : public Interface2<Implementation2<impl1>> {
    std::shared_ptr<Interface1<impl1>> imp1;
    void barimpl(typename typeHelp<Implementation2<impl1>>::type value) {
        std::cout << imp1->foo() << " " << value << std::endl;
    }
};

//Implementation1.hpp
struct Implementation1 : public Interface1<Implementation1> {
    double fooimpl() {return 0.;}
};

//Main.hpp
int main()
{
    Implementation2<Implementation1> obj;
    obj.imp1 = std::make_shared<Implementation1>();
    obj.bar(4);
}
Teloze
  • 279
  • 2
  • 8