Template argument deduction for member function pointers - c++

It is known that template arguments can be pointers to member functions.
So I can write:
struct Bar
{
int fun(float x);
};
template <int (Bar::*FUN)(float)>
struct Foo
{ /*...*/ };
typedef Foo<&Bar::fun> FooBar;
But what if I want the the Bar type itself to be a template argument:
template <typename B, int (B::*FUN)(float)>
struct Foo
{ /*...*/ };
typedef Foo<Bar, &Bar::fun> FooBar;
Now, when I use it, I have to write Bar twice!
My question is: Is there a way to force the compiler to deduce the class type automatically?
The objective is for this to just work:
typedef Foo<&Bar::fun> FooBar;
typedef Foo<&Moo::fun> FooMoo;

Simple answer: no there isn't.
The problem is that for typedef Foo<&Bar::fun> FooBar; to work, the template would have to have a single non-type argument, but the type of that argument would be unknown when the template is being declared, which is not valid. On the other side, type deduction is never applied to the arguments of the template (only to the arguments to function templates, but those are the arguments to the function, not the template).

You probably should just write the class name in there. However, if you really want to avoid that you can use the evil magic of macros. The simple version is more dangerous:
#define TT(X) decltype(X), X
template<typename T,T t>
struct Foo
{ /* ... */ };
struct Bar {
int fun(float) {}
};
int main() {
Foo<TT(&Bar::fun)> f;
}
This will accept any kind of non-type template parameter, and you may encounter hard-to-understand errors if the Foo implementation only works with pointers-to-member.
To make it a bit safer you need a metafunction that tells you the class name:
template<typename T> struct member_ptr_traits;
template<typename Class,typename Ret,typename... Args>
struct member_ptr_traits<Ret (Class::*)(Args...)>
{
typedef Class class_type;
typedef Ret return_type;
};
#define TT(X) member_ptr_traits<decltype(X)>::class_type , X
template<typename T,int (T::*FUN)(float)>
struct Foo
{ /* ... */ };
struct Bar {
int fun(float) {}
};
int main() {
Foo<TT(&Bar::fun)> f;
}
Also both of these use C++11 so they won't work with old compilers. This simple version can be rewritten to use the old typeof or similar compiler extensions. Rewriting the safer version requires simulating variadic templates.

Related

C++: What is the "<>" in std :: less<> [duplicate]

If I am allowed to do the following:
template <typename T = int>
class Foo{
};
Why am I not allowed to do the following in main?
Foo me;
But I must specify the following:
Foo<int> me;
C++11 introduced default template arguments and right now they are being elusive to my complete understanding.
Note:
Foo me; without template arguments is legal as of C++17. See this answer: https://stackoverflow.com/a/50970942/539997.
Original answer applicable before C++17:
You have to do:
Foo<> me;
The template arguments must be present but you can leave them empty.
Think of it like a function foo with a single default argument. The expression foo won't call it, but foo() will. The argument syntax must still be there. This is consistent with that.
With C++17, you can indeed.
This feature is called class template argument deduction and add more flexibility to the way you can declare variables of templated types.
So,
template <typename T = int>
class Foo{};
int main() {
Foo f;
}
is now legal C++ code.
You are not allowed to do that but you can do this
typedef Foo<> Fooo;
and then do
Fooo me;
You can use the following:
Foo<> me;
And have int be your template argument. The angular brackets are necessary and cannot be omitted.
Somewhat different case and rather later but where a template function is involved. gcc 11.2 can't seem to compile this:
template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
Test t;
foo<Test>(t);
}
but has no problem with
template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
Test t;
foo<Test<>>(t);
}
Of course
template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
Test t;
foo(t);
}
works - but sometimes you need to explicitly force the type. Is this a compiler bug?
As per the C++17 Standard, template arguments are necessary to be passed.
But if you still want a way around this, you can use using keyword like this
template <typename T>
class Foo{
};
using IFoo=Foo<int>
Or, you can also use preprocessor like this
template <typename T>
class Foo{
};
#define IFoo Foo<int>
Quick Reminder
Preprocessors are bad for debugging.

Why do struct & class templates need explicit angle brackets syntax on empty specialization? [duplicate]

If I am allowed to do the following:
template <typename T = int>
class Foo{
};
Why am I not allowed to do the following in main?
Foo me;
But I must specify the following:
Foo<int> me;
C++11 introduced default template arguments and right now they are being elusive to my complete understanding.
Note:
Foo me; without template arguments is legal as of C++17. See this answer: https://stackoverflow.com/a/50970942/539997.
Original answer applicable before C++17:
You have to do:
Foo<> me;
The template arguments must be present but you can leave them empty.
Think of it like a function foo with a single default argument. The expression foo won't call it, but foo() will. The argument syntax must still be there. This is consistent with that.
With C++17, you can indeed.
This feature is called class template argument deduction and add more flexibility to the way you can declare variables of templated types.
So,
template <typename T = int>
class Foo{};
int main() {
Foo f;
}
is now legal C++ code.
You are not allowed to do that but you can do this
typedef Foo<> Fooo;
and then do
Fooo me;
You can use the following:
Foo<> me;
And have int be your template argument. The angular brackets are necessary and cannot be omitted.
Somewhat different case and rather later but where a template function is involved. gcc 11.2 can't seem to compile this:
template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
Test t;
foo<Test>(t);
}
but has no problem with
template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
Test t;
foo<Test<>>(t);
}
Of course
template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
Test t;
foo(t);
}
works - but sometimes you need to explicitly force the type. Is this a compiler bug?
As per the C++17 Standard, template arguments are necessary to be passed.
But if you still want a way around this, you can use using keyword like this
template <typename T>
class Foo{
};
using IFoo=Foo<int>
Or, you can also use preprocessor like this
template <typename T>
class Foo{
};
#define IFoo Foo<int>
Quick Reminder
Preprocessors are bad for debugging.

Syntax for an instance of a class template as a non-type template parameter

I can't find the right syntax even after reading cppreference on template params. The following doesn't compile, but hopefully describes what I want to do. What's the correct syntax?
template <class DisplayType>
class DisplayAdapter : public DisplayType
{
};
template<template <typename> DisplayAdapter>
class Painter // Takes an instance of DisplayAdapter, not a type!
{
}
Here is how it's supposed to be used:
struct S{};
int main()
{
DisplayAdapter<S> concreteAdapter;
Painter<concreteAdapter> p;
return 0;
}
Here's Ideone snippet for the whole thing: https://ideone.com/dvbYt8
What you're wanting is not a template template parameter.
A template template parameter is used to pass templates around, like this:
template<template<typename> typename Container>
struct foo {
Container<int> container;
};
int main() {
foo<std::vector> f;
}
As you can see, you can pass template names around with that. Remember that templates are not types, but a blueprint for type, and the language (and the standard) is not treating templates the same way as types.
I assume with your examples your trying to use non-type template parameters?
A non-type template parameter is a template parameter that is a value instead of a type. It can be of any integral types, reference type and pointer type.
For example, look at std::array:
std::array<int, 10> tenInts;
Notice the second parameter is a number. This is because std::array look something like this:
template<typename T, std::size_t N>
struct array { /* ... */ };
The second parameter is an unsigned long int.
You can also pass references and pointers as template parameter:
template<int& i> struct foo {};
template<int* i> struct bar {};
int main() {
// Need at least internal linkage in C++14 and older
// No linkage required since C++17, only static needed.
static int num = 0;
foo<num> f;
bar<&num> b;
}
You can even pass a pointer to any type as reference template parameter:
struct stuff {};
template<stuff& s> struct foo;
int main() {
static stuff s{};
foo<s> f; // works!
}
This seem to be closer to what you wanted. However, you seem to have many many different type you want to send as template parameter, as the type of the instances you want to pass around are templated. For that you'll need C++17 template auto feature:
template<auto& da>
struct Painter {
// ...
};
int main() {
static DisplayAdapter<S> concreteAdapter;
Painter<concreteAdapter> p;
}
And done!
If you don't have C++17 with you don't worry, and simply pass the display type along with your instance (C++14 example):
template<typename DT, DisplayAdapter<DT>& da>
struct Painter {};
// Internal linkage
DisplayAdapter<S> da;
int main() {
Painter<S, da> painter;
}
If it was some simple type like int you would just use type instead of typename keyword e.g
template <int x>
or
template <std::vector<int>::value_type x>
But you can't put object of arbitrary type here.
More about non-type template parameters can be found in another Q&A
You need to add class before DisplayAdater
template <class DisplayType>
class DisplayAdapter : public DisplayType
{
};
template<template <typename> class DisplayAdapter>
class Painter // Takes an instance of DisplayAdapter, not a type!
{
};
https://godbolt.org/g/mV7YRC

Template Specialisation with Template Argument

Let's suppose to have a templateclass Foo:
template <typename T>
class Foo {
void foo();
};
I have another template class Bar (independent from the first one):
template <int N>
class Bar {};
Let's say, I want to specialise the foo() method for whatever Bar class.
I'd wrongly write:
template <>
template <int N>
void Foo<Bar<N> >::foo() { /* ... */ }
The compiler blames me for because the type is not complete:
error: invalid use of incomplete type 'class Foo<Bar<N> >'
void Foo<Bar<N> >::foo() { }
Code
I am using C++98, but I'd like to know if there exist different solutions in C++11.
Note
I could solve the problem specialising the entire class Foo for a generic Bar, but after I should have to define all methods.
Example Code
That's not what I want, I am looking for (if exists) more elegant solution (both C++98 and C++11) which allows me to specialise and implement only a single class method.
EDIT:
The question on SO does not explain how to specialise with a template argument. Indeed, my question shows how the compiler complains about that.
For C++11 you can SFINAE enable/disable (using std::enable_if) two differents versions of foo() inside a not specialized Foo class.
In C++98 you don't have std::enable_if but you can simulate it (give me some minutes and I try to propose an example). Sorry: my idea doesn't works because this method require the use of default template arguments for methods that is a C++11 innovation.
Another way is define a template base class for Foo(), say FooBase, insert foo() (and only foo()) in FooBase and specialize FooBase.
Another way, that works also with C++98, can be tag dispatching: you can define an unique foo(), with zero parameter, that call another foo(), with a parameter that is determined by T.
The following is a full (C++98 compilable) example
#include <iostream>
struct barWay {};
struct noBarWay {};
template <int>
struct Bar
{ };
template <typename>
struct selectType
{ typedef noBarWay type; };
template <int N>
struct selectType< Bar<N> >
{ typedef barWay type; };
template <typename T>
struct Foo
{
void foo (noBarWay const &)
{ std::cout << "not Bar version" << std::endl; }
void foo (barWay const &)
{ std::cout << "Bar version" << std::endl; }
void foo ()
{ foo(typename selectType<T>::type()); }
};
int main ()
{
Foo<int> fi;
Foo< Bar<42> > fb;
fi.foo();
fb.foo();
}
if a common base is not desirable, yet another way could be giving foo() a customization point, like a trait for example:
template <typename T>
struct foo_traits;
template <typename T>
struct Foo {
void foo(){ foo_traits<T>::foo_cp(*this); }
};
template <typename T>
struct foo_traits{ static void foo_cp(T&){/*default*/} };
template <int N>
class Bar {};
template <int N>
struct foo_traits<Bar<N>>{ static void foo_cp(Foo<Bar<N>>&){/*spec*/} };
such trait could also be an implementation detail friend, if its only purpose is to internally provide a foo() specialization for Bar's.
If you cannot specialize foo, define it so that it delegates the call to an internal foo-implementation class. Then specialize that class.
Something like this should compile in C++98 and it doesn't differ much from your original code:
template <typename T>
class Foo {
template<typename>
struct FooImpl;
public:
void foo() { FooImpl<T>()(); }
};
template <int N>
class Bar {};
template <typename T>
template <int N>
struct Foo<T>::FooImpl< Bar<N> > {
void operator()() { /* ... */ }
};
int main() {
Foo< Bar<0> > fb;
fb.foo();
Foo<int> fi;
//fi.foo();
}
The last line doesn't compile as expected (at least I got it was the expected result, just define the function call operator for FooImpl otherwise).
This way you can define selectively the specializations for which you want foo to work. In all the other cases, an attempt at using foo will result in a compilation error.
I'd like to know if there exist different solutions in C++11.
This is a classic use case for tagged dispatch, of which max66 already suggested. The approach, and even syntax, are basically the same in C++98 and C++11.
Here's a bit of a cleaner implementation than max66's, I believe (running on godbolt):
template <class T>
class Foo {
template <class>
struct tag{};
template<class U>
void foo_helper(tag<U>){std::cout << "default\n";}
void foo_helper(tag<Bar<3> >){std::cout << "specialization for Bar<3>\n";}
public:
void foo(){return foo_helper(tag<T>());}
};
The principle is the same; a client function accepting no arguments calls a helper function that constructs an empty type based on the T argument. Then normal overloading takes care of the rest.
Only here I use a templated catch-all method.
In C++11 the syntax would only change slightly; We could say tag<Bar<3>> instead of tag<Bar<3> > because new parsing rules allow the chevron for nested templates.
We could also make the tag and the templated foo_helper catch-all into variadic templates to be a little more generic:
template <class T>
class Foo {
template <class...>
struct tag{};
template<class... U>
void foo_helper(tag<U...>){std::cout << "default\n";}
void foo_helper(tag<Bar<3>>){std::cout << "specialization for Bar<3>\n";}
public:
void foo(){return foo_helper(tag<T>{});}
};
Things actually start getting pretty interesting in C++17 with the introduction of constexpr if that allows us to write what looks like normal branching logic based on T (Live Demo):
template <class T>
class Foo {
public:
void foo(){
if constexpr (std::is_same_v<T, Bar<3>>){std::cout << "Specialization for Bar<3>\n";}
else std::cout << "default\n";
}
};
As you can see, all the tag stuff goes away in favor of using a simple if statement.
We take advantage of type_traits introduced in C++11 to check the type of T against our desired type. Something like this wouldn't necessarily work previously because all branches needed to be compiled. In C++17, only the branch that is selected (at compile-time) is compiled.
Note that you could emulate this behavior as early as C++98 by using typeid (godbolt demo):
void foo(){
if (typeid(T) == typeid(Bar<3>)){std::cout << "Specialization for Bar<3>\n";}
else std::cout << "default\n";
}
However, the typeid approach is a poor choice for 2 reasons:
It's a run time check (slow) for information we know at compile-time
It's brittle because all branches must compile for all template instantiations, whereas in C++17 if constexpr only compiles the branch that is selected.

Template default arguments

If I am allowed to do the following:
template <typename T = int>
class Foo{
};
Why am I not allowed to do the following in main?
Foo me;
But I must specify the following:
Foo<int> me;
C++11 introduced default template arguments and right now they are being elusive to my complete understanding.
Note:
Foo me; without template arguments is legal as of C++17. See this answer: https://stackoverflow.com/a/50970942/539997.
Original answer applicable before C++17:
You have to do:
Foo<> me;
The template arguments must be present but you can leave them empty.
Think of it like a function foo with a single default argument. The expression foo won't call it, but foo() will. The argument syntax must still be there. This is consistent with that.
With C++17, you can indeed.
This feature is called class template argument deduction and add more flexibility to the way you can declare variables of templated types.
So,
template <typename T = int>
class Foo{};
int main() {
Foo f;
}
is now legal C++ code.
You are not allowed to do that but you can do this
typedef Foo<> Fooo;
and then do
Fooo me;
You can use the following:
Foo<> me;
And have int be your template argument. The angular brackets are necessary and cannot be omitted.
Somewhat different case and rather later but where a template function is involved. gcc 11.2 can't seem to compile this:
template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
Test t;
foo<Test>(t);
}
but has no problem with
template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
Test t;
foo<Test<>>(t);
}
Of course
template <typename T = int>
struct Test {};
template<typename T> void foo(T& bar) {}
int main()
{
Test t;
foo(t);
}
works - but sometimes you need to explicitly force the type. Is this a compiler bug?
As per the C++17 Standard, template arguments are necessary to be passed.
But if you still want a way around this, you can use using keyword like this
template <typename T>
class Foo{
};
using IFoo=Foo<int>
Or, you can also use preprocessor like this
template <typename T>
class Foo{
};
#define IFoo Foo<int>
Quick Reminder
Preprocessors are bad for debugging.