2

I'm trying to use the "using-declaration" syntax of C++ to expose some methods and operators of a templated base class. I can expose some methods and operators of the base class, but not a templated operator of the templated base class.

Here is an example of what I am trying, I'd like to be able to expose the templated operator A<> in class B.

template <typename T>
struct A
{
private:
    T _t;
public:
    A( T t ) : _t( t ) {}
    T operator()() const { return _t; }
    template <typename V>
    operator A<V>() const { return _t; }
};

template <typename T>
struct B : protected A<T>
{
public:
    using A<T>::A;             // ok
    using A<T>::operator();    // ok
//    template<typename V>
//    using A<T>::operator A<V>; // compile error
};

int main()
{
    int w = A<int>( 10 )();
    double x = static_cast<A<double>>( A<int>( 10 ) )();
    int y = B<int>( 10 )();
//    double z static_cast<B<double>>( B<int>( 10 ) )();
    return 0;
}

Is there any way to do this in C++11 (or higher)?

1 Answers1

0

I'd like to be able to expose the templated operator A<> in class B.

You are missing a conversion constructor in B and you also need to implement the user defined conversion operator in B.

You could do it by a cast to const A<T>& which you then cast to A<V> which will then use the user defined conversion operator in A:

template <typename T>
struct B : protected A<T> {
public:
    B(const A<T>& a) : A<T>(a) {}  // Slicing converting constructor

    using A<T>::A;           // ok
    using A<T>::operator();  // ok   

    template <typename V>
    operator B<V> () const {
        // cast *this to a `const A<T>&` and then use the
        // templated operator A<V> and finally the B<V> converting
        // constructor to create the return value:
        B<V> rv(static_cast<A<V>>(static_cast<const A<T>&>(*this)));

        // copy members in B to avoid slicing:
        rv.foo = static_cast<V>(foo);
         
        return rv;
    }

    T foo; // added member in B
};

Note that any member variables to add to B will be sliced away in the conversion sequence when you go through the conversion via A so you need to copy those manually.

Demo


If you don't care about slicing, then simply add the converting constructor and cast *this to const A<T>& in Bs user defined conversion operator and return A<V> which will then use As user defined conversion operator:

template <typename T>
struct B : protected A<T> {
public:
    B(const A<T>& a) : A<T>(a) {}  // Slicing converting constructor

    using A<T>::A;           // ok
    using A<T>::operator();  // ok   

    template <typename V>
    operator A<V> () const {
        return static_cast<const A<T>&>(*this);
    }
};

Demo

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • This is good! Thank you! But I think this does the same: `return static_cast>( *this )()`. Without needing to overload the constructor. – rubikssolver4 Mar 01 '23 at 20:48
  • @rubikssolver4 No, that won't even compile - well, it _will_ if you keep it `operator A () const` instead of `operator B () const` - but then you'll slice away any extra members you have in `B` like I showed – Ted Lyngmo Mar 01 '23 at 20:50
  • That is using the `operator A () const` since the output of that static cast is of type `A()`. It compiles fine for me. – rubikssolver4 Mar 01 '23 at 20:53
  • @rubikssolver4 `B bd(B(10));` - Do you want it to do a partial conversion, dropping the values of all members unique to `B` or do you want _all_ members to be converted and assigned to the members in `db`? – Ted Lyngmo Mar 01 '23 at 20:55
  • Yes, I am working on a dimensional typing library so the only member of interest is the underlying datatype. – rubikssolver4 Mar 01 '23 at 20:57
  • @rubikssolver4 Right, then the correct cast would be `static_cast&>(*this);` without the conversion constructor, `B bd(B(10));` won't be possible. – Ted Lyngmo Mar 01 '23 at 21:05
  • @rubikssolver4 Since the question is still up I wonder if I answered your _"I'd like to be able to expose the templated `operator A<>` in class `B`"_ request or if there's anything missing in my answer? – Ted Lyngmo Mar 16 '23 at 15:33