Overload of variadic template function with another template - c++

I am trying to figure out how to "overload" a variadic function template with a "more specialized" variadic function template. For example:
#include <iostream>
template <typename... ARGS_>
void foo(void(*fn)(ARGS_...)) {
std::cout << "Generic function pointer foo" << std::endl;
}
struct Test {
};
template <typename... ARGS_>
void foo(void(*fn)(ARGS_..., Test*)) {
std::cout << "Test function pointer foo" << std::endl;
}
void test1(int a, int b) {
std::cout << "test1()" << std::endl;
}
void test2(int a, int b, Test* x) {
std::cout << "test2()" << std::endl;
}
int main() {
foo(&test1);
foo(&test2);
return 0;
}
The output of this code is:
Generic function pointer foo
Generic function pointer foo
Rather than:
Generic function pointer foo
Test function pointer foo
as I want.
Conceptually, I am trying to notate "Use template method A if you have any type(s) of arguments where the LAST on is Test* and use template method B if the last type is NOT Test*."
What is the correct method to accomplish this type of behavior?

SFINAE'd overloads based on the last parameter pack argument
You can add mutually exclusive overloads based on whether the last type in the variadiac parameter pack is Test* or not:
#include <type_traits>
template <typename... Ts>
using last_t = typename decltype((std::type_identity<Ts>{}, ...))::type;
struct Test {};
template <
typename... ARGS_,
std::enable_if_t<!std::is_same_v<last_t<ARGS_...>, Test *>> * = nullptr>
void foo(void (*fn)(ARGS_...)) {
std::cout << "Generic function pointer foo" << std::endl;
}
template <
typename... ARGS_,
std::enable_if_t<std::is_same_v<last_t<ARGS_...>, Test *>> * = nullptr>
void foo(void (*fn)(ARGS_...)) {
std::cout << "Test function pointer foo" << std::endl;
}
// Special case for empty pack (as last_t<> is ill-formed)
void foo(void (*fn)()) { std::cout << "Zero args" << std::endl; }
making use if C++20's std::type_identity for the last_t transformation trait.
Used as:
void test1(int, int b) {}
void test2(int, int b, Test *x) {}
void test3(Test *) {}
void test4() {}
int main() {
foo(&test1); // Generic function pointer foo
foo(&test2); // Test function pointer foo
foo(&test3); // Test function pointer foo
foo(&test4); // Zero args
}
Avoiding the zero-arg special case as an overload?
The zero-arg foo overload can be avoided in favour of tweaking the last_t trait into one which also accepts an empty pack, such that a query over the empty pack is used to resolve to the generic overload. Neither its semantics nor its implementation becomes as straight-forward and elegant, however, as "the last type in an empty type list" does not make much sense, meaning the trait need to be tweaked into something different:
template <typename... Ts> struct last_or_unique_dummy_type {
using type = typename decltype((std::type_identity<Ts>{}, ...))::type;
};
template <> class last_or_unique_dummy_type<> {
struct dummy {};
public:
using type = dummy;
};
template <typename... Ts>
using last_or_unique_dummy_type_t =
typename last_or_unique_dummy_type<Ts...>::type;
template <typename... ARGS_,
std::enable_if_t<!std::is_same_v<
last_or_unique_dummy_type_t<ARGS_...>, Test *>> * = nullptr>
void foo(void (*fn)(ARGS_...)) {
std::cout << "Generic function pointer foo" << std::endl;
}
template <typename... ARGS_,
std::enable_if_t<std::is_same_v<last_or_unique_dummy_type_t<ARGS_...>,
Test *>> * = nullptr>
void foo(void (*fn)(ARGS_...)) {
std::cout << "Test function pointer foo" << std::endl;
}
Using an additional overload for the empty pack is likely the least surprising approach.
C++20 and the identity_t trick
In case you are not yet at C++20, an identity meta-function is trivial to write yourself:
template <typename T>
struct type_identity {
using type = T;
};
Any specialization of this class template, unless partially/explicitly specialized otherwise (which is UB for the STL type), is trivial and default-constructible. We leverage this in the definition of last_t above: default-constructing a series of trivial types in an unevaluated context, and leveraging that the last of those types embeds the input to the identity trait whose specialization is that trivial type, and whose wrapped alias declaration type is the type of the last parameter in the variadic parameter pack.

Check that the last element of ARGS... is Test*.
It won't do that for you this way. One ways is:
template<class...Ts>
struct last_type {};
template<class T1, class T2, class...Ts>
struct last_type<T1, T2, Ts...>:last_type<T2, Ts...>{};
template<class T>
struct last_type<T>{
using type=T;
};
template<class...Ts>
using last_type_t = typename last_type<Ts...>::type;
now you just:
template <typename... ARGS_>
requires std::is_same_v<last_type_t<ARGS_...>, Test*>
void foo(void(*fn)(ARGS_...)) {
std::cout << "Test function pointer foo" << std::endl;
}
Live example.
Without concepts, you have to replace that requires clause:
template <typename... ARGS_,
std::enable_if_t<std::is_same_v<last_type_t<ARGS_...>, Test*>, bool> = true
>
void foo(void(*fn)(ARGS_...)) {
std::cout << "Test function pointer foo" << std::endl;
}
which is a more obscure "cargo cult" way to basically say the same thing. (you also need to invert enable if clause in the other overload; not = false but !, and handle 0 arg case (prepend void on the type list?))
The reason why your attempt doesn't work is that C++ makes ... matching insanely greedy. It is generally not a good idea to put things you want pattern matched behind it in a context where pattern matching of parameters is done.

Related

Partial specialization for class method

I'm trying to specialize a method of a (non-templated!) class. Apparently, it's not possible, however I am struggling to figure out why, or how to overcome the problem.
class MyClass {
public:
template <typename... T>
auto MyMethod(T... t) -> void { std::cout << "Original" << std::endl; }
template <typename... T>
auto MyMethod<int, T...>(int value, T... t) -> void { std::cout << "Specialization" << value << std::endl; }
};
int main(void) {
MyClass myClass;
myClass.MyMethod<char, char>('c', 'c');
myClass.MyMethod<int, char>(123, 'c');
return 0;
}
The error is as follows:
test.cpp:10:49: error: non-class, non-variable partial specialization ‘MyMethod<int, T ...>’ is not allowed
10 | auto MyMethod<int, T...>(int value, T... t) -> void { std::cout << "Specialization" << value << std::endl; }
It seems that there would be no reason for this to be impossible (with a template class it makes sense that the entire class has to be specialized too). What am I missing? Is it literally not possible?
Only classes can be partially specialized; methods can only be fully specialized. As your methods still have template arguments (T) that are not specified, this means a partial method specialization.
If you would use these template arguments for a class (and call a non-templated member function of that class) then this should be possible.

Forcing C++ to prefer an overload with an implicit conversion over a template

I have a situation where I need overload resolution to prefer an overload with an implicit conversion over a template function with the same name.
Consider the following example:
#include <iostream>
#include <functional>
void call_function(const std::function<void()>& function)
{
std::cout << "CALL FUNCTION 1" << std::endl;
function();
}
template <typename Function>
void call_function(const Function& function)
{
std::cout << "CALL FUNCTION 2" << std::endl;
function();
}
int main()
{
// Pass a lambda to "call_function"
// This lambda is implicitly convertible to 'std::function<void()>'
// Even though it is implicitly convertible, the template function is selected by the compiler.
call_function([]{
std::cout << "TEST" << std::endl;
});
}
Output:
CALL FUNCTION 2
TEST
Unfortunately, the compiler seems to detect that the first implementation of call_function would require an implicit conversion to convert the lambda I pass it into a std::function<void()> object and because of this it determines that the template version is a better match and uses the template. I need to force the compiler to prefer the implicit conversion overload over the template so the output would be:
CALL FUNCTION 1
TEST
How can I achieve this? (Also note that I am restricted to a C++11 compliant compiler so I am unable to use features from C++14 and beyond)
Overload resolution will never prefer an implicit conversion over an exact match. Since the template will always match exactly, the only way to get the non-template selected is to assure that it doesn't require any conversion either.
To do that, you can cast the closure (the result of the lambda expression) to the correct type first:
call_function(static_cast<std::function<void()>>([]{
std::cout << "TEST" << std::endl;
}));
Now what's passed is exactly the type taken by the first overload ("FUNCTION 1") so that's what'll be selected.
That said, if you care about which one is called, you probably shouldn't be using overloading. Overloading should normally be reserved for situations where the overloads are essentially equivalent, so you really don't care which gets called.
If you want to change the overloads such that the former overload is chosen whenever there is an implicit conversion possible, with the latter being the backup, you can do this with SFINAE via std::enable_if:
#include <type_traits>
void call_function(const std::function<void()>& function)
{
std::cout << "CALL FUNCTION 1" << std::endl;
function();
}
template <typename Function,
// Consider this overload only if...
typename std::enable_if<
// the type cannot be converted to a std::function<void()>
!std::is_convertible<const Function&, std::function<void()>>::value,
int>::type = 0>
void call_function(const Function& function)
{
std::cout << "CALL FUNCTION 2" << std::endl;
function();
}
Demo
Alternatively, if you want to be able to support an unknown number of overloads of call_function with the "CALL FUNCTION 2" being a backup overload in case none of the functions work, you can do this too, but it requires quite a bit more work:
// Rename the functions to `call_function_impl`
void call_function_impl(const std::function<void()>& function)
{
std::cout << "CALL FUNCTION 1" << std::endl;
function();
}
void call_function_impl(const std::function<void(int, int)>& function)
{
std::cout << "CALL FUNCTION 2" << std::endl;
function(1, 2);
}
// The backup function must have a distinct name
template <typename Function>
void call_function_backup_impl(const Function& function)
{
std::cout << "CALL FUNCTION backup" << std::endl;
function();
}
// Implement std::void_t from C++17
template <typename>
struct void_impl {
using type = void;
};
template <typename T>
using void_t = typename void_impl<T>::type;
// Make a type trait to detect if the call_function_impl(...) call works
template <typename Function, typename = void>
struct has_call_function_impl
: std::false_type
{};
template <typename Function>
struct has_call_function_impl<Function,
void_t<decltype(call_function_impl(std::declval<const Function&>()))>>
: std::true_type
{};
// If the call_function_impl(...) call works, use it
template <typename Function,
typename std::enable_if<
has_call_function_impl<Function>::value,
int>::type = 0>
void call_function(const Function& function)
{
call_function_impl(function);
}
// Otherwise, fall back to the backup implementation
template <typename Function,
typename std::enable_if<
!has_call_function_impl<Function>::value,
int>::type = 0>
void call_function(const Function& function)
{
call_function_backup_impl(function);
}
Demo

class member overload (or specialization) based on different enum values

Is it possible to overload or specialize class member functions based on given enum values?
enum class Type {
TypeA,
TypeB,
TypeC
};
class Foo {
public:
template <Type t, typename R = std::enable_if_t<t==Type::TypeA, int>>
R get() {
return 1;
}
template <Type t, typename R = std::enable_if_t<t==Type::TypeB, double>>
R get() {
return 2;
}
template <Type t, typename R= std::enable_if_t<t==Type::TypeC, float>>
R get() {
return 3;
}
};
Foo foo;
std::cout << foo.get<Type::TypeA>() << std::endl;
std::cout << foo.get<Type::TypeB>() << std::endl;
std::cout << foo.get<Type::TypeC>() << std::endl;
The compile complain about overloading on above code snippet.
One pretty standard way to fix it is to put the std::enable_if clause in the return type of the function, rather than in the template parameters like that.
This compiles for me at c++11 standard.
#include <iostream>
#include <type_traits>
enum class Type {
TypeA,
TypeB,
TypeC
};
class Foo {
public:
template <Type t>
typename std::enable_if<t==Type::TypeA, int>::type get() {
return 1;
}
template <Type t>
typename std::enable_if<t==Type::TypeB, double>::type get() {
return 2;
}
template <Type t>
typename std::enable_if<t==Type::TypeC, float>::type get() {
return 3;
}
};
static_assert(std::is_same<int, decltype( std::declval<Foo>().get<Type::TypeA>())>::value, "");
static_assert(std::is_same<double, decltype( std::declval<Foo>().get<Type::TypeB>())>::value, "");
static_assert(std::is_same<float, decltype( std::declval<Foo>().get<Type::TypeC>())>::value, "");
int main() {
Foo foo;
std::cout << foo.get<Type::TypeA>() << std::endl;
std::cout << foo.get<Type::TypeB>() << std::endl;
std::cout << foo.get<Type::TypeC>() << std::endl;
}
I'm not sure if I can explain in detail why this change makes such a difference for the compiler.
However, consider the following. With your version, although you are never actually instantiating get with two explicit template parameters, technically all three of those member functions templates can "collide" and produce functions with exactly the same name. Because, if you did instantiate get<Type::TypeB, int>, then it would have the same return type, input parameters, and name as get<Type::TypeA>. C++ does not support function template specialization, it would make overload resolution rules very complicated. So having function templates with the potential to collide like this can make the compiler very upset.
When you do it the way I showed, there is no possibility that the templates can collide and produce a function with the same name and signature.
You can avoid the use of std::enable_if mapping the Type and return types specializing a simple struct (Bar, in the following example)
#include <iostream>
enum class Type {
TypeA,
TypeB,
TypeC
};
template <Type t>
struct Bar;
template <>
struct Bar<Type::TypeA>
{ using type = int; };
template <>
struct Bar<Type::TypeB>
{ using type = double; };
template <>
struct Bar<Type::TypeC>
{ using type = float; };
class Foo {
public:
template <Type t>
typename Bar<t>::type get();
};
template <>
Bar<Type::TypeA>::type Foo::get<Type::TypeA> ()
{ return 1; }
template <>
Bar<Type::TypeB>::type Foo::get<Type::TypeB> ()
{ return 2.2; }
template <>
Bar<Type::TypeC>::type Foo::get<Type::TypeC> ()
{ return 3.5f; }
int main ()
{
Foo foo;
std::cout << foo.get<Type::TypeA>() << std::endl;
std::cout << foo.get<Type::TypeB>() << std::endl;
std::cout << foo.get<Type::TypeC>() << std::endl;
return 0;
}
Your example doesn't compile because defaulted type templated parameters are not part of the function signature. So as far as the compiler is concerned, you are defining the same function multiple times, which is illegal. Instead, you need to use a defaulted non-type template parameter.
class Foo {
public:
template <Type t, std::enable_if_t<t==Type::TypeA, int> = 0>
int get() {
return 1;
}
template <Type t, std::enable_if_t<t==Type::TypeB, int> = 0>
double get() {
return 2;
}
template <Type t, std::enable_if_t<t==Type::TypeC, int> = 0>
float get() {
return 3;
}
};
Two working solutions are already posted; so why did I post this one? Well, I like it better. To be concrete:
It keeps what the function actually takes and returns separate from when it's enabled. This makes the function easier to read and understand. You can pull the code snippet from the second argument into a tiny macro called REQUIRE or similar; this makes it extremely clear what's going on. Neither of the other two answers posted have this property.
This technique is more universal; it can be used in slightly different situations with constructors, which don't return anything and cannot be used with the other two solutions
max66's approach of mapping the enum to a type is nice and it's something you should be aware of. It's more appropriate though when you can write the body generically; if you have to write out every implementation body separately anyhow, it only adds boilerplate (IMHO). Also you should be aware that a solution based on specialization is fragile; it doesn't work if there's a second template parameter nor if the class Foo is a class template, because of the restrictions on specialization function templates.
With the macro I mentioned above you could write it this way:
template <Type t, REQUIRE(t==Type::TypeA)>
int get() {
return 1;
}
// ...
Which I think is as good as it gets.

Call function template overload for derived variadic class template

I have a variadic class template deriv which derives off variadic class template base.
I have a function template which takes any type T, and an overload for base<Ts...> types;
How can I get the base<Ts...> overload to be used when passing a const deriv<Ts...>&?
Working example below:
#include <iostream>
#include <tuple>
template<typename... Ts>
struct base
{
std::tuple<Ts...> tuple;
};
template<typename... Ts>
struct deriv : base<Ts...>
{
};
//--------------------------------
template<typename T>
void func(const T&)
{
std::cout << "T" << std::endl;
}
template<typename... Ts>
void func(const base<Ts...>&)
{
std::cout << "base<Ts...>" << std::endl;
}
//----------------------------------------
int main()
{
int a;
base <int, double> b;
deriv<int, double> c;
func(a);
func(b);
func(c); // <--- I want func<base<Ts...>> not func<T> to be called here
exit(0);
}
Output from exemplar:
T
base<Ts...>
T
What I want the output to be:
T
base<Ts...>
base<Ts...>
Unless you are ready to re-engineer your code, you cannot, and for a good reason.
Your non-variadic overload of func() is a better match than the variadic version: in fact, when attempting to resolve your function call, the type parameter T for the non-variadic overload will be deduced to be derived<int, double>.
On the other hand, the parameter pack Ts in your variadic overload will be deduced to be int, double. After type deduction, this will practically leave the compiler with these two choices for resolving your call:
void func(const deriv<int, double>&); // Non-variadic after type deduction
void func(const base<int, double>&); // Variadic after type deduction
Which one should be picked when trying to match a call whose argument is of type derived<int, double>?
deriv<int, double> c;
func(c);
Obviously, the first, non variadic overload is a better match.
So how do you get the second overload called instead of the first? You have a few choices. First of all, you can qualify your call by explicitly specifying the template arguments:
func<int, double>(c);
If you do not like that, maybe you can re-think the definition of the non-variadic overload of func(): do you really want it to accept any possible type T? Or are there some types for which you know this overload is not to be invoked? If so, you can use SFINAE techniques and std::enable_if to rule out the undesired matches.
As a further possibility, you can relax a bit the signature of your template function and allow deducing its argument as an instantiation of a certain template class:
template<template<typename...> class T, typename... Ts>
void func(const T<Ts...>&)
{
std::cout << "base<Ts...>" << std::endl;
}
This change alone should fix your program's behavior in the way you want.
UPDATE:
If you want your specialized function template to be invoked only for classes derived from any instance of the base<> class template, you can use the std::is_base_of<> type trait and std::enable_if in the following way:
template<template<typename...> class T, typename... Ts>
void func(
const T<Ts...>&,
typename std::enable_if<
std::is_base_of<base<Ts...>, T<Ts...>>::value
>::type* = nullptr
)
{
std::cout << "base<Ts...>" << std::endl;
}
ADDENDUM:
In those situations where template function overloading won't help with your design, notice that you can always resort to partial template specialization. Unfortunately, function templates cannot be specialized, but you can still exploit class template partial specialization and add a helper function to hide the instantiation of that template. This is how you would rewrite your code:
namespace detail
{
template<typename T>
struct X
{
static void func(const T&)
{
std::cout << "T" << std::endl;
}
};
template<template<typename...> class T, typename... Ts>
struct X<T<Ts...>>
{
static void func(const T<Ts...>&)
{
std::cout << "base<Ts...>" << std::endl;
}
};
}
template<typename T>
void func(const T& t)
{
details::X<T>::func(t);
}
The generic-template overload is a better match, since it requires no conversion (except adding const, which both overloads have).
You can get the base-template overload by adding an explicit cast (example):
func(static_cast<base<int, double> &>(c));
(Alternatively, you could forgo the multiple overloads and instead stick some is_base_of helper logic into your main function template's body.)

Trying to use a template non-type parameter with an unknown type [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is it possible to emulate template<auto X>?
Consider the following working code:
#include <iostream>
template<typename T> struct Traits {};
template<typename T, typename A>
struct Traits<void(T::*)(A)>
{
typedef T Class;
typedef A Arg;
};
template<typename T, typename U, void(T::*MemFun)(U)>
void Builder()
{
std::cout << typeid(T).name() << std::endl;
std::cout << typeid(U).name() << std::endl;
std::cout << typeid(MemFun).name() << std::endl;
}
template<typename T, T arg>
void Builder()
{
return Builder<Traits<T>::Class,Traits<T>::Arg,arg>();
}
class Class
{
public:
void foo(int) { }
};
int main()
{
Builder<decltype(&Class::foo), &Class::foo>();
}
What I'd like to be able to do is something like this to get the same result, without using a macro.
int main()
{
Builder<&Class::foo>();
}
I can't seem to create a template that takes the pointer to member and deduces the type. Any thoughts? The pointer to member must be used as a template argument as opposed to a function parameter because it's used to create a template function (not shown).
Cannot be done. To have a non-type template argument you must provide the type. So either you limit your Builder to only one particular type or else you need an extra argument (first in the list) that is the type of second argument. Now, if you are willing not to use the member pointer as a constexpr... that is simple.
template <typename T, typename M>
struct Builder {
M T::*ptr;
Builder( M T::*ptr ) : ptr(ptr) {}
};
template <typename T, typename M>
Builder<T,M> createBuilder( M T::*ptr ) {
return Builder<T,M>(ptr);
}
int main() {
auto bld = createBuilder( &Class::member );
}
I have spent some time trying to do a similar thing myself.
I don't think it is possible without using the name of the function Class::foo twice. My reasoning is as follows:
to get the type of foo we must either use decltype or give foo as an argument to a template function
in any of the above, the constexpr-ness of foo (allowing it to be used as a template argument) is lost
moreover, we cannot "duplicate" foo inside a template class or function, as it would face the same problem as above
conclusion: we have to type foo twice at the outer scope
It seems one cannot get away without "dirty" macro tricks, even in C++11...
Unfortunately there's no way to do type deduction for the type of non-type template parameters. A macro is really the only option here.