Automatic template deduction for function pointers - c++

In the following code
template<class T> void f(T);
int main(){
f(3);
return 0;
}
the template argument int for deduces automatically, as usual.
But in
template<class T> void f(T);
template<class T> void (*p)(T) = f<T>;
int main(){
p(3);
return 0;
}
the compiler (clang++) insists that p(3) needs a template parameter. Why?
Besides, if I put the line template<class T> void (*p)(T) = f<T>; in a header to be included by several files, will that cause problems?

Template argument deduction works with function templates and and with CTAD from C++17. Writing a wrapper is trivial for your example.
template<class T> void f(T);
template<class T> void (*p)(T) = f<T>;
template<typename T> void Wrapper(T&& t)
{
p<T>(std::forward<T>(t));
}
int main(){
Wrapper(3);
}

Related

Specialize member function of class template using C++20 concepts

I want to specialize a member function of a class template as follows:
#include <concepts>
template <typename T>
struct S {
void f();
};
template <typename T>
void S<T>::f() {
}
// (0) This is fine.
template <>
void S<int>::f() {
}
// (1) This triggers an error.
template <std::integral T>
void S<T>::f() {
}
The specialization (0) is fine, but specializes f() only for the int type. Instead, I would like to specialize it, e.g., for any integral type, as in (1). Is this possible using C++20 concepts? Notice that std::integral is just an example and that my specific case makes use of user-defined concepts.
Simply use a trailing requires-clause. The compiler will choose the most constrained function:
#include <concepts>
#include <iostream>
template <typename T>
struct S {
void f();
void f() requires std::integral<T>;
};
template <typename T>
void S<T>::f() {
std::cout << "general\n";
}
template <typename T>
void S<T>::f() requires std::integral<T> {
std::cout << "constrained\n";
};
int main() {
S<int> x;
S<double> y;
x.f(); // prints constrained
y.f(); // prints general
return 0;
}

Rules for partial specialization of templates with nontype parameter(s)

Consider the following template
template <typename T, int v> void func(const T&x);
and I want to specialize it for some class A. Here is my try (by referring to this):
template <int v> void func<A, v>(const A&x);
However, that's illegal. My question is why this is illegal (which rule it breaks) and if that is against the grammar, is there other ways for us to specialize it for A?
You cannot partially specialize a function template but you can overload it as shown below.
#include <iostream>
class A
{
};
template <typename T, int v> void func(const T&x) //primary template
{
std::cout<<"primary template"<<std::endl;
}
//this is an overload and not a specialization. Also partial specialization cannot be done for function templates
template <int v> void func(const A&x)
{
std::cout<<"overload not specialization"<<std::endl;
}
int main()
{
func<int, 5>(84); //uses primary template
func<5>(A()); //uses the overloaded version
return 0;
}
Function templates cannot be partially specialized, hence the error:
<source>:8:23: error: non-class, non-variable partial specialization 'func<A, v>' is not allowed
8 | template <int v> void func<A, v>(const A&x);
| ^~~~~~~~~~
You can for example partially specialize a type with operator():
template <typename T, int v>
struct func{
void operator()(const T&x);
};
struct A {};
template <int v>
struct func<A, v>{
void operator()(const A&x);
};
You can use constraint (or SFINAE) to do it.
#include <iostream>
class A {};
class B {};
template <typename T, int v> void func(const T&)
{
std::cout<<"generic";
}
template <typename T, int v> void func(const T&)
requires std::is_same_v<T,A>
{
std::cout<<"A";
}
int main(){
func<A,1>(A{}); // output A
}
https://godbolt.org/z/YcxeoofYE
Realize v is not deduced here, which may cause undesired effect, leave this here as it maybe useful for someone reach this question.
you can do it with
template <typename T, int v> void func(const T&x);
template <int v> void func(const A&x);
as for why, I think it mainly because it provide no additional value
template <typename T> void func(const T&x);
template <typename T> void func(const T*x);
void func(const A&);
is already a valid function "specialization". not really specialization in the sense of standard wording

Have a template parameter that can be pointer type or non-pointer type

Suppose I have something like:
template <class T>
void do_something(T t){
pass_it_somewhere(t);
t->do_something();
}
Now it would be useful that T is allowed to be a pointer- or a non-pointer type. Function do_something(...) can basically handle pointers and non-pointers, except for the t->do_something(). For pointers, I would need a -> and for non-pointers, I would need a . to access members.
Is there a way to make T accept pointers and non-pointers?
You could create a dereference mechanism as below:
template<typename T>
std::enable_if_t<std::is_pointer<T>::value, std::remove_pointer_t<T>&> dereference(T& t) {
return *t;
}
template<typename T>
std::enable_if_t<!std::is_pointer<T>::value, T&> dereference(T& t) {
return t;
}
and use it in your function as:
template <class T>
void do_something(T t){
pass_it_somewhere(dereference(t));
dereference(t).do_something();
}
Live Demo
This way you'll have to do only with concrete versions of T.
Soultion 1
Use template specialization:
template <class T>
void do_something(T t){
pass_it_somewhere(t);
t.do_something();
}
template <class T>
void do_something(T* t){
pass_it_somewhere(t);
t->do_something();
}
Solution 2
Add a user-defined pointer operator in class T:
class A
{
public:
void do_something() const {}
const A* operator->() const { return this; }
};
template <class T>
void do_something(T t){
pass_it_somewhere(t);
t->do_something();
}
Yet another solution: tag dispatching.
namespace detail {
struct tag_value {};
struct tag_ptr {};
template <bool T> struct dispatch { using type = tag_value; };
template <> struct dispatch<true> { using type = tag_ptr; };
template <class T>
void do_call(T v, tag_value)
{
v.call();
}
template <class T>
void do_call(T ptr, tag_ptr)
{
ptr->call();
}
}
Then your function becomes:
template <class T>
void do_something(T unknown)
{
do_call(unknown,
typename detail::dispatch<std::is_pointer<T>::value>::type{} );
// found by ADL
}
Live Example.

Specializing member function template of a non-template class

Is the following specialization of the member function template bar valid? It compiles on gcc 4.5.3 and VS .NET 2008. I'm confused because I vaguely recall reading that function templates cannot be specialized.
struct Foo
{
template<typename T>
void bar();
};
template<typename T>
void Foo::bar(){}
template<>
void Foo::bar<bool>(){}
int main()
{
Foo f;
f.bar<char>();
f.bar<bool>();
}
Function template can not be partially specialized, but can be explicitly specialized, your code is perfectly correct.
Function template partial specialization was considered in C++11 but was rejected since function template overloading can be used to solve the same issue. However, there're some caveats which have to be looked for when doing this.
Example:
template <typename T> void foo(T);
void foo(int);
foo(10); // calls void bar(int)
foo(10.f); // calls void bar(T) [with T = float]
foo(10u); // calls void bar(T) [with T = unsigned int]!!
For your case, something of this sort might work
struct Foo
{
template<typename T>
void bar(T dummy);
void bar(bool dummy);
};
template<typename T>
void Foo::bar(T dummy) { }
void Foo::bar(bool dummy) { }
int main()
{
Foo f;
f.bar('a');
f.bar(true);
}

When a compiler can infer a template parameter?

Sometimes it works sometimes not:
template <class T>
void f(T t) {}
template <class T>
class MyClass {
public:
MyClass(T t) {}
};
void test () {
f<int>(5);
MyClass<int> mc(5);
f(5);
MyClass mc(5); // this doesn't work
}
Is there a way to hack around the example above? I.e. force the compiler to infer the template parameter from constructor parameter.
Will this be fixed in the future, or is there a good reason not to?
What is the general rule when compiler can infer template parameter?
Template parameters can be inferred for function templates when the parameter type can be deduced from the template parameters
So it can be inferred here:
template <typename T>
void f(T t);
template <typename T>
void f(std::vector<T> v);
but not here:
template <typename T>
T f() {
return T();
}
And not in class templates.
So the usual solution to your problem is to create a wrapper function, similar to the standard library function std::make_pair:
template <class T>
class MyClass {
public:
MyClass(T t) {}
void print(){
std::cout<<"try MyClass"<<std::endl;
}
};
template <typename T>
MyClass<T> MakeMyClass(T t) { return MyClass<T>(t); }
and then call auto a = MakeMyClass(5); to instantiate the class.
Read up on Template Argument Deduction (and ADL or Koenig lookup).
Since C++20, it is possible to infer the types of function parameters using auto:
#include <iostream>
#include <string>
auto print_stuff(auto x, auto y)
{
std::cout << x << std::endl;
std::cout << y << std::endl;
}
int main()
{
print_stuff(3,"Hello!");
print_stuff("Hello!",4);
return 0;
}