I'd like to have "hiding by signature" instead of "hiding by name" in c++. So I wrote a macro which defines a variadic function that delegates all calls to it's base class if some exists. I can't use a using declaration because I don't want it to fail if the base class has no method with that name - and inherited methods should be considered only if no direct member matches. And this works most of the time because it is implemented by a variadic function which are always worse candidates compared to non variadic functions. But I have a problem when the child class has a variadic function, too -> the call becomes ambiguous.
So I get the following situation (simplified - without sfinae, macro...):
#include <type_traits>
#include <iostream>
class A{
public:
void Do(){
std::cout << "A::Do()\n";
}
};
class B : public A
{
public:
template<
typename... TX,
typename SomeSFINAE = int
>
void Do(TX...){
std::cout << "B::Do()\n";
}
template<typename... T>
void Do(T...){
A::Do();
}
};
int main(){
B b;
b.Do();
return 0;
}
See it on godbolt.
I'd like to solve this situation without making one of the method a "dispatcher-method". Is there a way to make one method a "worse candidate" to solve this ambiguity?
Update
It seems not to be clear what I really want to achieve. So here some "pseudo-code" with comments:
#include <type_traits>
#include <iostream>
class A{
public:
void Do(){
std::cout << "A::Do()\n";
}
};
class B : public A
{
public:
template<
typename... TX
>
void Do(TX...){
std::cout << "B::Do()\n";
}
using A::Do; //<--- This should be considered only if no direct match is found in B
//Variadic function should win, because it is defined in B not in A - it should hide A.Do
//It should even work if A has NO method Do
};
int main(){
B b{};
b.Do(); //-> B::Do should be called, not A::Do
return 0;
}
Update
What I want from you is something similar how you can make a normal function a worse candidate just for variadic functions.
For example:
#include <iostream>
void Do(int a){
std::cout << "better";
}
template<typename... T>
void Do(int a, T...){
//this is worse
std::cout << "worse";
}
int main(){
Do(42);
return 0;
}
Is there something which can make variadic function even worse?
Background: Currently I have the following macro, just to emulate a using like I want it.
#define NATIVE_DO_NOT_HIDE_INHERITED_(AMETHOD, ...) \
private: template<typename $T, typename... $Args> \
using CallHiding$ ## AMETHOD = decltype(::std::declval<$T*>()->AMETHOD (::std::declval<$Args>()...)); \
\
public: template< \
typename... $Args \
, typename $Dependent = __VA_ARGS__ \
, bool $Detected = ::CORE_NATIVE_NS ::is_detected_v<CallHiding$ ## AMETHOD, $Dependent, $Args...> \
, typename = typename ::std::enable_if_t<$Detected > \
> \
constexpr decltype(auto) AMETHOD ($Args&&... args) \
{ \
/*allow virtual call*/ \
return static_cast<$Dependent*>(this) -> AMETHOD (::std::forward<$Args>(args)...); \
} \
\
private: template<typename $T, typename $FktArgsTuple, typename $ValueArgsTuple> \
class CallHidingGeneric$ ## AMETHOD : public ::std::bool_constant<false> {\
};\
\
private: template<typename $T, typename... $FktArgs, typename... $ValueArgs> \
class CallHidingGeneric$ ## AMETHOD<$T, ::std::tuple<$FktArgs...>, ::std::tuple<$ValueArgs...>> \
{\
template<typename AType> \
using ATemplate = decltype(::std::declval<AType>().template AMETHOD <$FktArgs...> (::std::declval<$ValueArgs>()...)); \
public: \
constexpr static bool value = ::CORE_NATIVE_NS ::is_detected_v<ATemplate, $T> ; \
}; \
\
public: template< \
typename... $FktArgs \
, typename... $Args \
, typename $Dependent = __VA_ARGS__ \
, typename = ::std::enable_if_t<(sizeof...($FktArgs) > 0)> \
, typename = ::std::enable_if_t< \
CallHidingGeneric$ ## AMETHOD<$Dependent, typename ::std::template tuple<$FktArgs...>, typename ::std::template tuple<$Args...>>::value \
> \
> \
constexpr decltype(auto) AMETHOD ($Args&&... args) \
{ \
return $Dependent ::template AMETHOD <$FktArgs...> (::std::forward<$Args>(args)...); \
}
#define NATIVE_DO_NOT_HIDE_INHERITED(AMETHOD) NATIVE_DO_NOT_HIDE_INHERITED_(AMETHOD, $Next)
#define NATIVE_DO_NOT_HIDE_INHERITED2(AMETHOD, ...) NATIVE_DO_NOT_HIDE_INHERITED_(AMETHOD, typename ::CORE_NATIVE_NS::type_container_t< __VA_ARGS__ >:: $Next)
It works fine with "normal" functions - but the "macro generated functions" are not considered worse...