Home > Mobile >  C partial specialization of template without code duplication
C partial specialization of template without code duplication

Time:12-11

I have a class definition with 3 template parameters. I would like to create specializations of this class with specific combinations of 2 of the parameters, leaving the third free. How can I do that without duplicating code?

template < typename A, typename B, class C> Foo{}; // only defining particular specializations

template<class C> Foo<int, float, C> 
{
   int V1;
   float V2;
   friend C;
   /* implementation using V1, V2 */
}

template<class C> Foo<bool, char, C> 
{
   bool V1;
   char V2;
   friend C;
  /* duplicate implementation using V1, V2 */
}

main {

Foo<bool, char someclassname> fbc;
Foo<int, float, otherclassname> fif;

}

CodePudding user response:

You can use concept

// or simply drop this if you don't need it
template <typename A, typename B, class C> 
struct Foo{};

template<typename A, typename B, class C>
requires std::same_as<A,int> && std::same_as<B,float>
      || std::same_as<A,bool> && std::same_as<B,char>
struct Foo<A, B, C> 
{
   A V1;
   B V2;
   friend C;
   /* implementation using V1, V2 */
};

or inherit from a common base class

template <typename A, typename B, class C> 
struct Foo{};

template <typename A, typename B, class C> 
struct Foo_impl 
{
   A V1;
   B V2;
   friend C;
   /* implementation using V1, V2 */
};

template<class C>
struct Foo<int,float,C>:Foo_impl<int,float,C>{};

template<class C>
struct Foo<bool,char,C>:Foo_impl<int,float,C>{};

if you don't need the default case, you can also static_assert it

template <typename A, typename B, class C> 
struct Foo{
   static_assert(std::is_same_v<A,bool> && std::is_same_v<B,char>
       || std::is_same_v<A,int> && std::is_same_v<B,float>);
   A V1 = 10;
   B V2;
   friend C;
   /* implementation using V1, V2 */
};

CodePudding user response:

My original question above was not detailed enough and did not compile. I found the solution as a combination of the advices above. Thanks to all the responders. Here I post the full example (compiles with C 20)

#include <type_traits>
#include <concepts>


enum class TypeID: int { INTEGER=1, FLOAT};
// abstract base class, defines interface for a RTTI mechanism
class Base
{
public:
    Base() {};
    virtual ~Base() {};
    virtual TypeID GetID() = 0;  // RTTI
};


template< typename V, TypeID ID, class F>
class Numeric : public Base
{
    static_assert(
        (std::same_as<V, int> && TypeID::INTEGER ==ID) || 
        (std::same_as<V, float> && TypeID::FLOAT == ID) 
        , "Error message here");

    friend F;

    public:
        Numeric(V argValue=0) { V1 = argValue; };
        virtual ~Numeric(){};
        TypeID GetID() { return ID; }

        V GetValue() { return V1; }

    protected:
        V V1=0;
        void SetValue(V argValue) { V1 = argValue; }

};

template <class F> using NumericInt = Numeric<int, TypeID::INTEGER, F>;
template <class F> using NumericFloat= Numeric<float, TypeID::FLOAT, F> ;

class FriendlyClass {
public:
    FriendlyClass(int argInitial) { mN.SetValue(argInitial); };
private:
    NumericInt<FriendlyClass> mN= NumericInt<FriendlyClass>();
};


int main(){

    NumericInt<FriendlyClass>  N1(1); // OK
    NumericFloat<FriendlyClass>  N2(2); // OK
    Numeric<int, TypeID::INTEGER, FriendlyClass>  N3(3); // same as alias NumericInt , but OK

    Numeric<int, TypeID::FLOAT, FriendlyClass>  N4(4); // NOT ok, will static_assert()

return 0;

};
  • Related