Call function template overload for derived variadic class template - c++

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.)

Related

No matching function call for lambda function parameter to template function

Trying to pass a lambda function to a template factory function which is templated on the function arguments of the passed function leads gcc-10.2.0 to report no matching function for call to ‘test(main()::<lambda(int, double)>)’.
It does seem to work when I add a + in front of the lambda function forcing the conversion to a function pointer, but I don't see why that would be necessary. Why does the conversion not happen automatically? Is there any way to make this work?
I have also tried std::function<void(TArgs...)> test_func as argument in the declaration of make_test, however that gives me the same no matching function for call error.
#include <iostream>
template <typename... TArgs>
struct test_type {
test_type(void(TArgs...)) {};
};
template <typename... TArgs>
test_type<TArgs...> make_test(void test_func(TArgs...)) {
return test_type<TArgs...>{test_func};
}
int main() {
auto test_object = make_test([](int a, double b) { std::cout << a << b << "\n"; });
return 0;
}
Edit
I was wondering if there maybe is some way to make it work with type traits. Something like the following. Although I know of no way to get the argument list from the template parameter.
template <typename F>
test_type<get_arg_list<F>> make_test(std::function<F>&& f) {
return test_type<get_arg_list<F>>{std::forward(f)};
}
In order to support a variety of callables being passed to your factory (e.g., a stateful lambda or a function pointer), your test_type constructor should accept some kind of type-erased function type like std::function<void(int, double)>:
template<class... TArgs>
struct test_type {
test_type(std::function<void(TArgs...)>) {};
};
Afterwards it's just a matter of writing the boilerplate to handle the following callables being passed to make_test
a regular function pointer
a lambda (struct with a operator()(...) const)
a mutable lambda or a user defined callable without a const operator() function
Here is one approach using type traits:
Start with a base class that we'll specialize for each scenario:
template<class T, class = void>
struct infer_test_type;
(This is a common setup for the voider pattern. We can do this with concepts and constraints, but I'm feeling too lazy to look up the syntax, maybe later)
Regular function pointer specialization
template<class Ret, class... Args>
struct infer_test_type<Ret(*)(Args...)>
{
using type = test_type<Args...>;
};
Now we can write a templated alias for simplicity:
template<class T>
using infer_test_type_t = typename infer_test_type<T>::type;
And we can verify that it works like so:
void foo(int, double){}
// ...
static_assert(std::is_same_v<infer_test_type_t<decltype(&foo)>, test_type<int, double>>);
We can use the type trait for our make_test function like so:
template<class T>
auto make_test(T&& callable) -> infer_test_type_t<T>
{
return infer_test_type_t<T>{std::forward<T>(callable)};
}
Now it's just a matter of covering our other two scenarios.
Callable objects
these will have operator() (either const or not)
I'll start with a top level trait to detect the presence of operator() and feed the type of operator() into another trait.
The top level trait:
// if T is a callable object
template<class T>
struct infer_test_type<T, std::void_t<decltype(&T::operator())>>
{
using type = typename infer_test_type<decltype(&T::operator())>::type;
};
You see that internally it's calling back into another infer_test_type specialization that I haven't shown yet; one that is specialized for operator(). I'll show the two specializations now:
// if operator() is a const member function
template<class T, class Ret, class... Args>
struct infer_test_type<Ret(T::*)(Args...) const>
{
using type = test_type<Args...>;
};
// if operator() is non-const member function
template<class T, class Ret, class... Args>
struct infer_test_type<Ret(T::*)(Args...)>
{
using type = test_type<Args...>;
};
(We could probably combine these two if we wanted to be a little bit smarter and lop off any const at the high level before calling down, but I think this is more clear)
And now we should be able to infer an appropriate test_type for non-generic callables (no generic lambdas or templated operator() functions):
a test with a non-const operator():
struct my_callable
{
void operator()(int, double) // non-const
{
}
};
// ...
static_assert(std::is_same_v<infer_test_type_t<my_callable>, test_type<int, double>>);
And a test with your lambda:
auto lambda = [](int a, double b) { std::cout << a << b << "\n"; };
static_assert(std::is_same_v<infer_test_type_t<decltype(lambda)>, test_type<int, double>>);
Putting it all together
For your simple (non-capturing, non-generic lambda) example it's quite straightforward:
make_test([](int a, double b) { std::cout << a << b << "\n"; });
Demo

Templated functions overload return type

The following doesn't look like a partial specialization (that however cannot happen on a templated function). Plus functions don't overload by just return type. What's going on in the following code??
#include <iostream>
#include <string>
#include <vector>
template<typename T>
T foo() {
std::cout << "first";
return T();
}
template<typename T, typename U>
std::pair<T,U> foo() {
std::cout << "second";
return std::make_pair<T,U>(T(),U());
}
int main()
{
foo<int>();
foo<int,char>();
}
You have two overloads of foo (really two function templates named foo). One takes one template type argument:
template<typename T>
T foo();
And one takes two template type arguments:
template<typename T, typename U>
std::pair<T,U> foo();
You are allowed to overload on different template arguments. You could even add overloads that take non-type arguments:
template <int I>
void foo() {
std::cout << "third";
}
This is a separate, valid overload too. What you can't do is then separately add:
template <typename U>
U* foo();
Because now you have two different function templates named foo that take a single template argument and there's no way for the compiler to know which one you meant - so now you have a guaranteed ambiguous overload.
I won't call it overload , but compiler will generate two different functions based on template arguments.

C++ Understanding the exact semantics of templates, esp. with functional parameters

I'm comfortable using templates when they simply parameterize over a type. However, I'm now beginning to use them in more complex applications (specifically, parameterizing over a function, as in C++ Template: typename and function to map to int ), and have been reduced essentially to trial and error (note in the above referenced question I can't get my code to compile).
What are the exact semantics of the template keyword (or the typename keyword when used outside the definition of a template), especially when you want a function as a parameter?
How do I define a template that takes a function as a parameter?
Once defined, how do I instantiate and use that template?
I'll accept the first complete answer that includes both a compilable example as well as clear, full explanation, of what's going on behind the magic?
CLARIFICATION: I understand how to use typename. My question is: What are the exact semantics of template definition, especially when applied to invocable parameters? and How do you define and instantiate a class which takes a function (or functor or something invokable) as a template parameter?
What are the exact semantics of the template and typename keywords, especially when you want a function as a parameter?
template introduces a template declaration (and also declarations of explicit instantiations and specialisations, but that's beyond the scope of this question). It's followed by the list of template parameters, in angle brackets <>.
Within that list, typename or class introduces a type parameter; one of three kinds of parameter, the others being non-type (value) parameters, and template parameters.
How do I define a template that takes a function as a parameter?
The simplest way is with a type parameter, which can be any type that can be called like a function; for example
template <typename F, typename... Args>
void call(F && f, Args &&... args) {f(std::forward<Args>(args)...);}
Once defined, how do I instantiate and use that template?
If it's a function template, simply call the function with appropriately typed arguments. The template parameters will be deduced from them:
void f1(int a, double b); // function
struct fn {
void operator()(std::string);
};
call(f1, 42, 1.5);
call(fn{}, "Hello");
call([](std::string s){std::cout << s}, "Lambda\n");
For class templates, you'd have to specify the function type, which can be a bit messy:
template <typename F>
struct thing {
F f;
};
thing<void(*)(int,double)> thing1 {f1};
thing<fn> thing2 {fn{}};
// Lambdas are problematic since the type has no name
//thing<???> thing3 {[]{std::cout << "Lambda\n";}};
The messiness could be avoided by using a factory function template to deduce the function type and instantiate the class template:
template <typename F>
thing<F> make_thing(F && f) {
return thing<F>(std::forward<F>(f));
}
auto thing1 = make_thing(f1);
auto thing2 = make_thing(fn{});
auto thing3 = make_thing([]{std::cout << "Lambda\n";});
Below some example (commented) code to show how functions can be used in a template. You can replace typename Parameter with typename... Parameter and p to p... if you want the first template to work for any number of fucntion arguments, which uses variadic templates.
#include <functional> // for std::function
#include <iostream>
// example functions
void func(int i)
{
std::cout << "Integer: " << i << ".\n";
}
int gunc(int i)
{
int result = i+1;
std::cout << "+Integer:" << result << ".\n";
return result;
}
// general non-restrictive template
template<typename Function, typename Parameter>
void call_twice(Function f, Parameter p)
{
f(p);
f(p);
}
// Restrict signature to void(int), but the return value can be anything: it will be ignored
void call_thrice(std::function<void(int)> f, int p)
{
f(p);
f(p);
f(p);
}
// Restrict signature to int(int), to exclude func
void call_four_times(std::function<int(int)> f, int p)
{
f(p);
f(p);
f(p);
f(p);
}
int main()
{
call_twice(func, 1); // instantiates void call_twice(void (*)(int), int)
call_twice(gunc, 1); // instantiated void call_twice(int (*)(int), int)
// Note I do not write the explicit types of func and gunc in the above comments, they're not important!
call_thrice(func, 10); // converts func to a std::function<void(int)>
call_thrice(gunc, 10); // return value can be ignored, so int(int) is convertible to void(int)
//call_four_times(func, 100); // will fail to compile: cannot convert a function of signature void(int) to one with signature int(int)
call_four_times(gunc, 100); // converts gunc to std::function<int(int)>
}
Live demo here.
The basic form of a template declaration starts anything of the form
template<typename T>
template<class T> // same as above
template<int N> // explicitly typed template parameter, need not be an int
template<typename... variadic_template_args>
And of course the forms with combinations of the above, including nested template types and all. Just remember the variadic template parameter must come last.
Templates are what the name implies: a blueprint to create a class with certain functionality expressed within the template definition.
Instantiation occurs when you actually call a template function (from either another instantiated template function or a non-template function), or for class templates, when you declare an object of the type, e.g. for std::vector:
std::vector<double> v; // instantiate the class template std::vector for type double
This is no different to templates that take functions as arguments. Note that functions decay to function pointers when passed to another function.
For example, a class template with a function as template parameter:
#include <iostream>
#include <type_traits> // for std::result_of
template<typename Function, Function f>
struct A
{
using function_type = Function;
template<typename... ArgTypes>
typename std::result_of<Function(ArgTypes...)>::type call(ArgTypes... args)
{
return f(args...);
}
};
void func(int i) { std::cout << "Integer: " << i << ".\n"; }
int main()
{
A<decltype(&func), func> a;
a.call(42);
}
Live demo here. Note the extra & in the decltype, because a function only decays to a function pointer when it is passed to a function, not when it is used as a template parameter. Note the "extra" typename before the std::result_of: this is required because its type typedef is a dependent name. These and other times you need to use the template and typename keywords, those are covered in Where and why do I have to put the “template” and “typename” keywords?
It's easier to use lambdas
template <typename F>
void herp(F function)
{
function("Hello from herp");
}
int main()
{
const auto deDerp = [] (const std::string& msg)
{
std::cout << msg << "\n";
};
herp(deDerp);
}

SFINAE: Compiler doesn't pick the specialized template class

I have an SFINAE problem:
In the following code, I want the C++ compiler to pick the specialized functor and print "special", but it's printing "general" instead.
#include <iostream>
#include <vector>
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename T::Vec> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
How can I fix it so that the specialized struct is used automatically? Note I don't want to directly specialize the Functor struct on Foo, but I want to specialize it on all types that have a Vec type.
P.S.: I am using g++ 4.4.4
Sorry for misleading you in the last answer, I thought for a moment that it would be simpler. So I will try to provide a complete solution here. The general approach to solve this type of problems is to write a traits helper template and use it together with enable_if (either C++11, boost or manual implementation) to decide a class specialization:
Trait
A simple approach, not necessarily the best, but simple to write would be:
template <typename T>
struct has_nested_Vec {
typedef char yes;
typedef char (&no)[2];
template <typename U>
static yes test( typename U::Vec* p );
template <typename U>
static no test( ... );
static const bool value = sizeof( test<T>(0) ) == sizeof(yes);
};
The approach is simple, provide two template functions, that return types of different sizes. One of which takes the nested Vec type and the other takes ellipsis. For all those types that have a nested Vec the first overload is a better match (ellipsis is the worst match for any type). For those types that don't have a nested Vec SFINAE will discard that overload and the only option left will be the ellipsis. So now we have a trait to ask whether any type has a nested Vec type.
Enable if
You can use this from any library, or you can roll your own, it is quite simple:
template <bool state, typename T = void>
struct enable_if {};
template <typename T>
struct enable_if<true,T> {
typedef T type;
};
When the first argument is false, the base template is the only option, and that does not have a nested type, if the condition is true, then enable_if has a nested type that we can use with SFINAE.
Implementation
Now we need to provide the template and the specialization that will use SFINAE for only those types with a nested Vec:
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename enable_if<has_nested_Vec<T>::value>::type > {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
Whenever we instantiate Functor with a type, the compiler will try to use the specialization, which will in turn instantiate has_nested_Vec and obtain a truth value, passed to enable_if. For those types for which the value is false, enable_if does not have a nested type type, so the specialization will be discarded in SFINAE and the base template will be used.
Your particular case
In your particular case, where it seems that you don't really need to specialize the whole type but just the operator, you can mix the three elements into a single one: a Functor that dispatches to one of two internal templated functions based on the presence of Vec, removing the need for enable_if and the traits class:
template <typename T>
class Functor {
template <typename U>
void op_impl( typename U::Vec* p ) const {
std::cout << "specialized";
}
template <typename U>
void op_impl( ... ) const {
std::cout << "general";
}
public:
void operator()() const {
op_impl<T>(0);
}
};
Even though this is an old question, I think it's still worth providing a couple more alternatives for quickly fixing the original code.
Basically, the problem is not with the use of SFINAE (that part is fine, actually), but with the matching of the default parameter in the primary template (void) to the argument supplied in the partial specialization(typename T::Vec). Because of the default parameter in the primary template, Functor<Foo> actually means Functor<Foo, void>. When the compiler tries to instantiate that using the specialization, it tries to match the two arguments with the ones in the specialization and fails, as void cannot be substituted for std::vector<int>. It then falls back to instantiating using the primary template.
So, the quickest fix, which assumes all your Vecs are std::vector<int>s, is to replace the line
template<class T, class V = void>
with this
template<class T, class E = std::vector<int>>
The specialization will now be used, because the arguments will match. Simple, but too limiting. Clearly, we need to better control the type of the argument in the specialization, in order to make it match something that we can specify as the default parameter in the primary template. One quick solution that doesn't require defining new traits is this:
#include <iostream>
#include <vector>
#include <type_traits>
template<class T, class E = std::true_type>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename std::is_reference<typename T::Vec&>::type> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
This will work for any Vec type that could make sense here, including fundamental types and arrays, for example, and references or pointers to them.
Another alternative for detecting the existence of a member type is to use void_t. As valid partial specialisations are preferable to the general implementation as long as they match the default parameter(s), we want a type that evaluates to void when valid, and is only valid when the specified member exists; this type is commonly (and, as of C++17, canonically) known as void_t.
template<class...>
using void_t = void;
If your compiler doesn't properly support it (in early C++14 compilers, unused parameters in alias templates weren't guaranteed to ensure SFINAE, breaking the above void_t), a workaround is available.
template<typename... Ts> struct make_void { typedef void type; };
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
As of C++17, void_t is available in the utilities library, in type_traits.
#include <iostream>
#include <vector>
#include <type_traits> // For void_t.
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
// Use void_t here.
template<class T>
struct Functor<T, std::void_t<typename T::Vec>> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
With this, the output is special, as intended.
In this case, since we're checking for the existence of a member type, the process is very simple; it can be done without expression SFINAE or the type_traits library, allowing us to rewrite the check to use C++03 facilities if necessary.
// void_t:
// Place above Functor's definition.
template<typename T> struct void_t { typedef void type; };
// ...
template<class T>
struct Functor<T, typename void_t<typename T::Vec>::type> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
To my knowledge, this should work on most, if not all, SFINAE-capable C++03-, C++11-, C++14-, or C++1z-compliant compilers. This can be useful when dealing with compilers that lag behind the standard a bit, or when compiling for platforms that don't have C++11-compatible compilers yet.
For more information on void_t, see cppreference.

C++: overloading does not choose expected method

I have the following code:
#include <iostream>
#include <vector>
using namespace std;
struct A{};
struct B: public A {};
template <typename T>
void foo(const T& obj) { cerr << "Generic case"<< endl;}
void foo(const A& a) {
cerr << "Specific case" << endl;
}
int main() {
vector<int> v;
foo(v);
B b;
foo(b);
A a;
foo(a);
}
Output is
Generic case
Generic case
Specific case
Why is it that foo(const A& a) is not being chosen for the B object ?
Curiously enough, if I removed the templated method and just have the following:
#include <iostream>
#include <vector>
struct A{};
struct B: public A {};
//template <typename T>
//void foo(const T& obj) { cerr << "Generic case"<< endl;}
void foo(const A& a) {
cerr << "Specific case" << endl;
}
int main() {
B b;
foo(b);
A a;
foo(a);
}
The code compiles and the output is:
Specific case
Specific case
Why is the presence of the templated method making such a difference?
Edit: How can I force the compiler to choose the free method for classes derived from A in the presence
of the templated method?
No conversion is necessary for the call to foo(const B&) which the template instantiation yields thus it is the better match.
When a function call is seen by the compiler, every base function template has to be instantiated and is included in the overload set along with every normal function. After that overload resolution is performed. There is also SFINAE, which allows an instantiation of a function template to lead to an error (such a function would not be added to the overload set). Of course, things aren't really that simple, but it should give the general picture.
Regarding your edit: There is only one method to call. What else could there be as output?
Yes, it is a bit surprising but inheritance and template don't mix so well when it come to overload resolution.
The thing is, when evaluating which overload should be selected, the compiler chooses the one that necessitates the least conversions (built-in to built-in, derived-to-base, calls to non-explicit constructors or conversion operators, etc...). The ranking algorithm is actually pretty complex (not all conversions are treated the same...).
Once the overloads are ranked, if the two top-most are ranked the same and one is a template, then the template is discarded. However, if the template ranks higher than the non-template (less conversions, usually), then the template is selected.
In your case:
for std::vector<int> only one overload matches, so it is selected.
for A two overloads match, they rank equally, the template one is discarded.
for B two overloads match, the template rank higher (no derived-to-base conversion required), it is selected.
There are two work-arounds, the simplest is to "fix" the call site:
A const& ba = b;
foo(ba);
The other is to fix the template itself, however this is trickier...
You can hardcode that for classes derived from A this is not the overload you wish for:
template <typename T>
typename std::enable_if<not std::is_base_of<A, T>::value>::type
foo(T const& t) {
std::cerr << "Generic case\n";
}
However this is not so flexible...
Another solution is to define a hook. First we need some metaprogramming utility:
// Utility
template <typename T, typename Result = void>
struct enable: std::enable_if< std::is_same<T, std::true_type>::value > {};
template <typename T, typename Result = void>
struct disable: std::enable_if< not std::is_same<T, std::true_type>::value > {};
And then we define our hook and function:
std::false_type has_specific_foo(...);
template <typename T>
auto foo(T const& t) -> typename disable<decltype(has_specific_foo(t))>::type {
std::cerr << "Generic case\n";
}
And then for each base class we want a specific foo:
std::true_type has_specific_foo(A const&);
In action at ideone.
It is possible in C++03 too, but slightly more cumbersome. The idea is the same though, an ellipsis argument ... has the worst rank, so we can use overload selection on another function to drive the choice of the primary one.
#pmr's answer explains why the templated function is preferred in your example. To force the compiler to pick your overload instead, you can make use of SFINAE to drop the templated function from the overload set. Change the templated foo to
template <typename T>
typename std::enable_if<!std::is_base_of<A, T>::value>::type
foo(const T& obj) { cerr << "Generic case"<< endl;}
Now, if T is A or a class derived from A the templated function's return type is invalid and it will be excluded from overload resolution. enable_if is present in the type_traits header.