Home > Back-end >  Template func with cond. const argument template arg deduction
Template func with cond. const argument template arg deduction

Time:10-26

I am implementing a wrapper class that wraps some base class object. I want the wrapper to be as unnoticeable as possible and therefore, I have already overloaded the -> operator to return a reference to the wrapped object in order to provide immediate access to the base-class's interface.

Additionally, I want my wrapper type to also implement all operators that the base-class implements and just delegates the respective operator calls to the wrapped object. However, since I want to be able to wrap any arbitrary base-class, I don't know a priori what operators are defined for the wrapped class.

My current approach consists of just defining all operators for my wrapper and using SFINAE to disable those implementations that are not covered by base-class implementations.

The implementation for the operator overload essentially always looks like this

auto operator <operator> (const Wrapper &lhs, const Wrapper &rhs) { return lhs.get() <operator> rhs.get(); }
auto operator <operator> (const Wrapper &lhs, const Base &rhs) { return lhs.get() <operator> rhs; }
auto operator <operator> (const Base &lhs, const Wrapper &rhs) { return lhs <operator> rhs.get(); }

where <operator> is the respective operator. Since, I don't want to duplicate this code for all operators, I have defined some macros to create the definitions for me.

This works for most operators, but now I also want to support the various assignment operators (e.g. *=). Here, the lhs argument must not be const as it is modified via the action of the operator.

I could just generate these separately, but I thought that there must be a way to simply make the lhs argument const or non-const depending on a constexpr boolean (available as macro-parameter). Thus, I created a templated helper cond_add_const< T, bool > that returns const T if passed true and T if passed false.

The problem now is, that the overloads that involve the Base class as direct parameters fail to be resolved due to template argument deduction failure. The problem seems to be that in order to apply my conditional const, I essentially have the replace the respective type with cond_add_const< T, true >::type and apparently everything to the left of :: does not participate in template argument deduction.

This seems rather frustrating and it also feels like for my simple case there should be a possibility to circumvent this limitation (or choose an approach that does not require it), but I just can't come up with one (that does not involve duplicating code). Any ideas?


MWE illustrating my problem:

#include <type_traits>

template< typename T, bool is_const > struct cond_add_const {
    using type = typename std::conditional< is_const, typename std::add_const< T >::type, typename std::remove_const< T >::type >::type;
};

template< typename T > void myFunc(typename cond_add_const< T, true >::type lhs, int rhs) {
}

int main() {
    myFunc(1, 2);
}

Compiling this snippet with g results in

test.cpp: In function ‘int main()’:
test.cpp:11:13: error: no matching function for call to ‘myFunc(int, int)’
   11 |  myFunc(1, 2);
      |             ^
test.cpp:7:29: note: candidate: ‘template<class T> void myFunc(typename cond_add_const<T, true>::type, int)’
    7 | template< typename T > void myFunc(typename cond_add_const< T, true >::type lhs, int rhs) {
      |                             ^~~~~~
test.cpp:7:29: note:   template argument deduction/substitution failed:
test.cpp:11:13: note:   couldn’t deduce template parameter ‘T’
   11 |  myFunc(1, 2);
      |

CodePudding user response:

You might turn your template functions in non-template friend function of your class:

template <typename T>
struct Wrapper
{
    // ...

    friend void myFunc(typename cond_add_const<Wrapper<T>, true >::type lhs, T rhs)
    { /*...*/ }
};

Demo

There are some caveats:

  • the friend function can only be found via "ADL" (So at least one parameter should be of the Wrapper type).
  • Related