0

I'm trying to generalize my class using policy-based design, and it seems that gcc doesn't see the implementation of pure virtual functions that are implemented in base classes. Here is an example:

#include <iostream>

template <typename ReturnValue, template <typename> class... AccessPolicies>
struct testInterface : public AccessPolicies< ReturnValue >::interface...
{

};

template <typename DataClass, typename ReturnValue, template <typename> class... AccessPolicies>
struct testImplementation :   public DataClass,
                              public testInterface< ReturnValue, AccessPolicies... >,
                              public AccessPolicies< ReturnValue >::template implementation< DataClass >...
{

};

template < typename ReturnValue >
struct GetByIndex;

template <>
struct GetByIndex< std::string >
{
    class interface
    {
    public:
        virtual std::string operator[](size_t ) = 0;
    protected:
        virtual ~interface() = default;
    };

    template <class DataClass>
    class implementation
    {
    public:
        virtual std::string operator[](size_t )
        {
            return "test by index";
        }
    protected:
        virtual ~implementation() = default;
    };
};

template < typename ReturnValue >
struct GetByName;

template <>
struct GetByName< std::string >
{
    class interface
    {
    public:
        virtual std::string operator[](std::string ) = 0;
    protected:
        virtual ~interface() = default;
    };

    template <class DataClass>
    class implementation
    {
    public:
        virtual std::string operator[](std::string )
        {
            return "test by string";
        }
    protected:
        virtual ~implementation() = default;
    };
};

struct data
{

};

int main()
{
    testImplementation< data, std::string, GetByIndex, GetByName> test;
    testInterface< std::string, GetByIndex, GetByName >& Test = test;

    std::cout << Test[5] << std::endl;

    return 0;
}

Errors I'm getting are:

..\nienazwany\main.cpp: In function 'int main()':
..\nienazwany\main.cpp:78:67: error: cannot declare variable 'test' to be of abstract type 'testImplementation<data, std::basic_string<char>, GetByIndex, GetByName>'
     testImplementation< data, std::string, GetByIndex, GetByName> test;
                                                                   ^
..\nienazwany\main.cpp:10:8: note:   because the following virtual functions are pure within 'testImplementation<data, std::basic_string<char>, GetByIndex, GetByName>':
 struct testImplementation :   public DataClass,
        ^
..\nienazwany\main.cpp:53:29: note:     virtual std::string GetByName<std::basic_string<char> >::interface::operator[](std::string)
         virtual std::string operator[](std::string ) = 0;
                             ^
..\nienazwany\main.cpp:26:29: note:     virtual std::string GetByIndex<std::basic_string<char> >::interface::operator[](size_t)
         virtual std::string operator[](size_t ) = 0;
                             ^
..\nienazwany\main.cpp:81:24: error: request for member 'operator[]' is ambiguous
     std::cout << Test[5] << std::endl;
                        ^
..\nienazwany\main.cpp:53:29: note: candidates are: virtual std::string GetByName<std::basic_string<char> >::interface::operator[](std::string)
         virtual std::string operator[](std::string ) = 0;
                             ^
..\nienazwany\main.cpp:26:29: note:                 virtual std::string GetByIndex<std::basic_string<char> >::interface::operator[](size_t)
         virtual std::string operator[](size_t ) = 0;

There are two problem's I don't quite get:

  1. The compiler seems to not consider AccessPolicy< ReturnType >::implementation< DataClass >... to be an implementation of AccessPolicy< ReturnType >::interface... even though the function signatures are exactly the same.
  2. The compiler cannot resolve which operator[] I'm calling even though they all have different arguments an I'm clearly calling the size_t one (numbers cannot be implicitly converted to strings).

Any ideas why is this happening?

My guess is that even though I'm inheriting directly from "interface" and "implementation" the member functions somehow end up in different namespaces. If that's correct, how do I get around this?


EDIT : added the above example stripped of the templates, as per request

#include <iostream>

class GetByIndexInterface
{
public:
    virtual std::string operator[](size_t ) = 0;
protected:
    virtual ~GetByIndexInterface() = default;
};

class GetByIndexImplementation
{
public:
    virtual std::string operator[](size_t )
    {
        return "test by index";
    }
protected:
    virtual ~GetByIndexImplementation() = default;
};


class GetByNameInterface
{
public:
    virtual std::string operator[](std::string ) = 0;
protected:
    virtual ~GetByNameInterface() = default;
};

class GetByNameImplementation
{
public:
    virtual std::string operator[](std::string )
    {
        return "test by string";
    }
protected:
    virtual ~GetByNameImplementation() = default;
};

struct data
{

};

struct testInterface : public GetByIndexInterface,
                       public GetByNameInterface
{

};

struct testImplementation :   public data,
                              public testInterface,
                              public GetByIndexImplementation,
                              public GetByNameImplementation
{

};

int main()
{
    testImplementation test;
    testInterface& Test = test;

    std::cout << Test[5] << std::endl;

    return 0;
}
tsuki
  • 907
  • 4
  • 17
  • Could you perhaps construct a simpler test-case that's easier to read? Perhaps eliminate all the complex template stuff for now? – Oliver Charlesworth Jan 26 '14 at 09:28
  • Added the equivalent test case without all of the templates. – tsuki Jan 26 '14 at 09:41
  • Thanks, that's much easier to follow! – Oliver Charlesworth Jan 26 '14 at 09:43
  • Might be related?: http://stackoverflow.com/questions/3686210/c-using-a-base-class-as-the-implementation-of-an-interface If I understand the code correctly it boils down to the same. The ambiguous operator would be a side effect I guess. –  Jan 26 '14 at 09:51
  • http://stackoverflow.com/questions/1313063/request-for-member-is-ambiguous-in-g – user2672165 Jan 26 '14 at 09:56
  • The thing is: if I make the implementations inherit from interfaces I get the same error. I already tried it before posting. I bet that inheriting `testImplementation` from `testInterface` makes the `getBy...Interfaces` separate from `GetBy...Implementations` – tsuki Jan 26 '14 at 10:06

2 Answers2

1

You're struct testImplementation is inheriting from struct testInterface itself inheriting from struct GetByNameInterface which defines an virtual std::string operator[](std::string ) = 0;

Neither testInterface nor testImplementation are defining an override for this virtual, so testImplementation is an abstract structure.

The fact that you're inheriting from another class that has no relation with the previous one but defines the same operator will not help you. You have to implement your method in a hierarchy between your concrete implementation and your abstract interface, not on a side class.

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
Johan
  • 3,728
  • 16
  • 25
  • @tsuki That won't help in an inheritance. There is a virtual function table defined for every class you're inheriting and the compiler needs to fill it with just the elements defined in you class and its ancestor in direct line to the one defining the virtual. The other inherited classes don't play in this game. – Johan Jan 26 '14 at 10:23
  • I deleted my post as soon as I notices your edit adding the last paragraph. Sorry. Any tips on how to get around this? – tsuki Jan 26 '14 at 10:27
  • @tsuki Do you really need a class hierarchy with virtual methods ? – Johan Jan 26 '14 at 10:31
  • Yes, I think so. The class I'm implementing is meant to be a heterogeneous container that will allow me to access it's data as if it was a simple struct, or by an array-like interface which would return a common type (std::string, for example). The array-like interface would be common for different types of underlying data structures and this is where I need virtual functions. My class works with a fixed set of virtual operator[], but I would like to be able to define which way I want to access the underlying data in array interface - by index, by name, or other ways I did not yet think of. – tsuki Jan 26 '14 at 10:51
  • @tsuki And do you reall need to implement the behaviour in an unrelated class ? Cannot implement everything in `testImplementation` I guess... – Johan Jan 26 '14 at 13:22
0

In order to do that you implementation class must inherit from your interface class, this way implementation will be accepted, but as said before inheriting from an unrelated class that has an implementation for an abstract function, does not mean that implemented function should considered as implementation of abstract function

BigBoss
  • 6,904
  • 2
  • 23
  • 38
  • If I get this right - I tried to make `implementation` inherit from `interface`, but it doesn't seem to work. – tsuki Jan 26 '14 at 10:55