Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ interface without inheritance for template functions

There are two different classes with intersecting set of methods:

class A {
public:
    int Value1() { return 100; }
    char Value2() { return "a"; }
    void actionA() { };
}

class B {
public:
    int Value1() { return 200; }
    char Value2() { return "b"; }
    void actionB() { };
}

The common part of the classes interface can be described like this:

class GenericPart {
public:
  virtual int Value1();
  virtual char Value2();
}

Please note that classes A and B come from some library and therefore cannot be inherited from GenericPart.

There is a template function that works with objects implementing methods described in GenericPart:

template <typename T>
void function(T record) {
    std::cout << record.Value1() << " " << record.Value2() << std::endl;
}

Is it possible to specialize this template function to make it receive only objects that match GenericPart?

like image 933
Vitaly Isaev Avatar asked Sep 07 '25 00:09

Vitaly Isaev


1 Answers

You could use the C++20 feature: concepts & constraints, but a simpler solution may involve static_assert. See the comments in function for some explanation

#include <type_traits>
#include <iostream>

class A {
public:
    int Value1() { return 100; }
    char Value2() { return 'a'; }
    void actionA() { };
};

class B {
public:
    int Value1() { return 200; }
    char Value2() { return 'b'; }
    void actionB() { };
};

class C  { // Has the required functions but with different return types
public:
    double Value1() { return 0.0; }
    double Value2() { return 1.0; }
};

class D  { // Has only one required function
public:
    int Value1() { return 300; }
};


template <typename T>
void function(T record) {
    // Check statically that T contains a `Value1()` that returns an int
    static_assert(std::is_same_v<int, decltype(record.Value1())>, "int Value1() required!");

    // Check statically that T contains a `Value2()` that returns an char
    static_assert(std::is_same_v<char, decltype(record.Value2())>, "char Value2() required!");

    std::cout << record.Value1() << " " << record.Value2() << std::endl;
}

int main()
{
    A a;
    B b;
    C c;
    D d;

    function(a); // Ok
    function(b); // Ok
    function(c); // causes static_assert to fail
    function(d); // causes static_assert to fail
}
like image 55
churill Avatar answered Sep 10 '25 08:09

churill