C++ Templates: Function as Template Class Parameter - c++

So in C++ we can pass functions as template parameters like so:
template <typename func>
int tester(func f)
{
return f(10);
}
So I have a template class which uses a function, and I've been using it like this, where each time I would pass the function and a variable to it.
template <typename type_t>
class TCl
{
...
template <typename func>
int Test(func f, type_t Var>
{
// Blah blah blah
}
};
But I would like to make the function one of the class template parameters to make it easier to use.
So I first tried this:
template <typename func>
template <typename type_t, func f>
class TCl
{
...
};
But when I compile this I get:
Compiler Error C3857: multiple type parameter lists are not allowed
Because God forbid my code should actually compile the first time I try it.
Now my problem has been that while I know the parameters types for the function (in this case size_t, size_t), the return type could be anything, so long as there is a proper comparison operator for type_t.
After several hours of reading online, I found a working solution.
template <typename type_t, typename ret_t, ret_t f(size_t, size_t)>
class TCl
{
...
};
While it work, it kind of ruins the aesthetic of the code. And I would greatly prefer something like in the original example where I specify a func type, and don't have to worry about specifying the return type.
So does anyone have any suggestions?
Also, no Boost.
EDIT:
SOLVED!
Thank you guys. I used Jarod42's solution.
#Drax & Lightness Races in Orbit:
I had considered placing the type before hand, but it would have placed the burden on the programmer to define the function pointer in order to use it, which seemed unnecessarily cruel :)
Jarod42 however solved that using macros and the decltype operator, which I had completely forgotten about.
There was a slight problem with your example Jarod42.
#define TCl_T(type_t, function) Tcl<type_t, decltype(function), function>
Generates an error:
error C1001: An internal error has occurred in the compiler.
This solves it.
#define TCl_T(type_t, function) Tcl<type_t, decltype(&function), function>
Apparently we have to specify that it is a pointer.
Once again, thanks for the help guys!

With:
template <typename type_t, typename ret_t, ret_t f(size_t, size_t)>
class TCl;
You may use a Macro:
#define TCl_T(type_t, function) Tcl<type_t, decltype(function(0, 0)), function>
And then use it like:
// bool my_func(size_t, size_t);
TCl_T(int, my_func) tcl; // tcl is a Tcl<int, bool, my_func>
And if you change TCl to:
template <typename type_t, typename prototype_t, prototype_t f>
class TCl;
You may use a Macro:
#define TCl_T(type_t, function) Tcl<type_t, decltype(function), function>

Well just put the template parameters on the same line :
template <typename type_t, typename func, func f>
class TCl
{
...
};

And I would greatly prefer something like in the original example where I specify a func type, and don't have to worry about specifying the return type.
Okay, so simply do that! :-) I don't understand why you have gone from passing the entire function type as a template argument, to splitting it up into return type and parameter types. And, in doing so, you introduced your stated problem. But you didn't explain why you made this change.
Why not simply:
template <typename type_t, typename func_t, func_t f>
class TCl
{
// ...
};
This is the logical evolution of your own approach, is it not?
Here's an example that works:
#include <iostream>
template <typename type_t, typename func_t, func_t f>
struct T
{
T() { f(); }
type_t a; /**< Irrelevant here, but gives your `type_t` something to do */
};
void foo() { std::cout << "A\n"; }
int bar() { std::cout << "B\n"; return 0; }
int main()
{
T<int, void(*)(), &foo> t1;
T<int, int (*)(), &bar> t2;
}
// Output:
// A
// B
Live demo
Shame you can't use more deduction in the template-argument-list. Jarod42 had an interesting idea with macros in order to shorten the call, though I'm not sure it improved the aesthetic.
I wonder whether this means that your assertion:
make the function one of the class template parameters to make it easier to use
is false.

Related

Specialize template which includes enableif

I want to specialize a templated method. It makes use of std::enable_if to check a static property of the given type:
template <class T, bool fancy= T::IsFancy()>
typename std::enable_if<fancy, void>::type
onlyForFancyGuys(T* component) {
/*stuff*/
onlyForFancyGuys(component->parent);
}
As I use this for recursive calls, I need a way to determine, when recursion ends. That is, when type Foo is used. So I tried this specialization.
template<>
typename void onlyForFancyGuys<Foo, true>(Foo* component);
and
template<>
void onlyForFancyGuys<Foo, true>(Foo* component);
But it keeps telling, me that this template-id does not match any template declaration. What am I doing wrong here? Is there something specific with enable_if?
Important fact: Foo does not have the method IsFancy.
Edit: I added IsFancy to Foo, but it does not make any difference.
Edit: I am compiling with MinGW. But I plan to use MSVC, too.
Edit: Adding IsFancy to Foo together with the accepted answer did the trick.
Just use overload:
void onlyForFancyGuys(Foo* component) { /* ... */ }
template <class T, bool fancy = T::IsFancy()>
typename std::enable_if<fancy, void>::type
onlyForFancyGuys(T* component) {
/*stuff*/
onlyForFancyGuys(component->parent);
}
template will be exclude thank to SFINAE (on T::IsFancy())
In:
template<>
typename void onlyForFancyGuys<Foo, true>(Foo* component);
Gid rid tof typename before void.
I think at some point in the recursion you are reaching the place where no template can be instantiated.
Try to declare the general template at the top which breaks the recursion first and then do the rest. There is some weird logic that I don't quite understand but I would try this at least to compile. I think that enable_if is not in the right place in your case. Would tipp at some design issues in general.
template<typename T>
void onlyForFancyGuys(T* t) {
}
and
template<typename T, bool b>
void onlyForFancyGuys(T* t) {
}
And remove typename before void in the specialization, like somebody said.

C++ template argument of unknown type

Suppose we want to write a function which is supposed to get a value as a template parameter (for, say, efficiency reasons), but we don't know in advance the type of the parameter we're expecting. It is possible to implement it as
template<typename T, T val>
func() { cout << val; }
However, it is not fun to call such a function
func<int, 5>()
is it possible to rewrite func s.t. we can call it in the following way?
func<5>()
A solution that mostly depends on your actual function is to define it as it follows:
template<typename T>
constexpr void func(T val) { }
Then invoke it as f(5) and have the template parameter deduced from the parameter of the function itself.
Otherwise, in C++14, you cannot avoid using the pattern template<typename T, T value>.
It is the same pattern used by the Standard Template Library, see as an example the definition of std::integral_constant.
A possible solution that mitigates (maybe) the boilerplate is based on the use of a struct, as an example:
template<typename T>
struct S {
template<T value>
static void func() {}
};
You can the do something like this:
using IntS = S<int>;
// ....
IntS::func<5>();
With the upcoming revision C++17, you will manage to do it as it follows:
template<auto value>
void func() {}
This can be invoked as f<5>(), that is what you are looking for..

C++ Template specialization with class as return type and enum as parameter

I don't have a lot of experience using templates but I'm trying to do template specialization based on enums with a function which returns different classes. Below is the sample code (or rather what I'm trying to accomplish):
class Foo {
// member variables
};
class Cat {
// member variables
};
enum MyType{ A, B, C};
// Header file
template<class T, MyType U> std_shared_ptr<T> process();
// cpp file / implementation
template<> std_shared_ptr<Foo> process<Foo, A>()
{
}
template<> std_shared_ptr<Cat> process<Cat, C>();
{
}
Can someone help me in figuring out what I'm missing here or doing wrong? I tried searching it and found some solutions for handling enum types (Template specialization for enum), however, can't figure out how to put it together with a template return type in a function.
EDIT:
What I'm trying do here is to do template specialization based on enum type as argument to a function. And the same function returns a template class as well. So the function has two templates here: T (return param) and U (input param which is an enum). Is it possible to do so?
EDIT:
Modified the above sample for the right behavior.
You cannot partially specialize template functions.
The value, not the type, of a function parameter cannot change the type of the return value. The value of a non-type template parameter can change the type of the return value, but that is passed within the <> and must be compile-time determined, not within the ()s.
Tags may help.
template<MyType X>
using my_type_tag_t=std::integral_constant<MyType, X>;
template<MyType X>
constexpr my_type_tag_t<X> my_type_tag = {};
template<class T>struct tag_t{using type=T;};
template<class Tag>using type=typename Tag::type;
template<MyType>
struct my_type_map;
template<>
struct my_type_map<MyType::A>:tag<Foo>{};
template<>
struct my_type_map<MyType::B>:tag<Cat>{};
then:
template<MyType X>
std::shared_ptr<type<my_type_map<X>>>
process( my_type_tag_t<X> );
where you call process( my_type_tag<A> ) to get a shared_ptr<Foo> out of it.
Implementations look like:
template<>
std::shared_ptr<Foo>
process( my_type_tag_t<MyType::A> ) {
// blah
}
still inelegant, and probably doesn't solve your problem, but it is close to your described solution.

How can I get the C++ compiler to deduce T indirectly?

My template-fu is rather weak. I have this code:
template<typename T>
void Foo(void(*func)(T*)) { }
void Callback(int* data) { }
int Test()
{
Foo(Callback);
}
...but I'd like something more readable than C's nasty function pointer syntax of void(*func)(T*).
Someone on my team suggested this:
template<typename T>
struct Types
{
typedef void Func(T*);
};
template<typename T>
void Foo2(typename Types<T>::Func* func) {}
void Test2()
{
Foo2(Callback); // could not deduce template argument for 'T'
Foo2<int>(Callback); // ok
}
(I'm still debating whether this is actually more readable, but that's a separate issue.)
How can I help the compiler figure out what T is without needing to explicitly specify it in the caller?
You can extract T from the function type using a traits class.
template<class F>
struct CallbackTraits;
template<class T>
struct CallbackTraits<void(*)(T)>
{
typedef T ArgumentType;
};
Your example can be modified like this:
template<typename F>
void Foo(F func)
{
typedef typename CallbackTraits<F>::ArgumentType T;
}
void Callback(int* data) { }
int Test()
{
Foo(Callback);
}
This technique is used in the boost type-traits library:
http://www.boost.org/doc/libs/1_57_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html
This blog post goes into a bit more detail about the implementation of the technique:
https://functionalcpp.wordpress.com/2013/08/05/function-traits/
Unfortunately this approach hides the information in the signature of Foo about the constraints on the argument passed in. In the above example the argument must be a function of type void(T*).
This alternative syntax does the same as the original example while being slightly more readable:
template<typename T>
void Foo(void func(T*)) { }
Another alternative syntax that may be more readable can be achieved using c++11's alias templates as follows:
template<typename T>
using Identity = T;
template<typename T>
void Foo(Identity<void(T*)> func) { }
Unforunately the latest MSVC fails to compile this, reporting an internal compiler error.
You won't be able to deduce the type based on a nested name: there is no reason why different instantiations of the outer type won't define an identical inner type. You could use a using alias, though:
template <typename T>
using Function = auto (*)(T*) -> void;
template <typename T>
void Foo(Function<T>) {
}
Personally, I would recommend against using any of that, however: in practice it seems much more advisable to actually take a function object which later allows using object with suitable function call operators to be used. For callbacks it is quite common that you'll need to pass in some auxiliary data. That is, you would either use an unconstrained template or one which takes a type-erased type, depending on what you want to do exactly:
template <typename Fun>
void Unconstrained(Fun fun) {
}
template <typename T>
void TypeErased(std::function<void(T*)> fun) {
}
The unconstrained version has the advantage that it can potentially inline the function call but it has the disadvantage that every function object type creates a new instantiation and that the argument types are likely to vary. The type-erased version effectively has to do something like a virtual function call but there is just one instantiation of the function template (per argument type T, of course).
Admittedly, the type-erased version's type won't be deduced from a function pointer (or any other argument which isn't a std::function<void(X*)>), i.e., you may want to have a forwarding function
template <typename T>
void TypeErased(Function<T> fun) {
TypeErased(std::function<void(T)>(fun));
}
In C++98 and C++03 template argument deduction only works with functions (and methods).
I don't think the picture changed in the more recent standards.

"What happened to my SFINAE" redux: conditional template class members?

I'm new to writing template metaprogramming code (vs. just reading it). So I'm running afoul of some noob issues. One of which is pretty well summarized by this non-SO post called "What happened to my SFINAE?", which I will C++11-ize as this:
(Note: I gave the methods different names only to help with my error diagnosis in this "thought experiment" example. See #R.MartinhoFernandes's notes on why you wouldn't actually choose this approach in practice for non-overloads.)
#include <type_traits>
using namespace std;
template <typename T>
struct Foo {
typename enable_if<is_pointer<T>::value, void>::type
valid_if_pointer(T) const { }
typename disable_if<is_pointer<T>::value, void>::type
valid_if_not_pointer(T) const { }
};
int main(int argc, char * argv[])
{
int someInt = 1020;
Foo<int*>().valid_if_pointer(&someInt);
Foo<int>().valid_if_not_pointer(304);
return 0;
}
#Alf says what happened to the SFINAE is "It wasn't there in the first place", and gives a suggestion that compiles, but templates the functions instead of the class. That might be right for some situations, but not all. (For instance: I'm specifically trying to write a container that can hold types that may or may not be copy-constructible, and I need to flip methods on and off based on that.)
As a workaround, I gave this a shot...which appears to work correctly.
#include <type_traits>
using namespace std;
template <typename T>
struct FooPointerBase {
void valid_if_pointer(T) const { }
};
template <typename T>
struct FooNonPointerBase {
void valid_if_not_pointer(T) const { }
};
template <typename T>
struct Foo : public conditional<
is_pointer<T>::value,
FooPointerBase<T>,
FooNonPointerBase<T> >::type {
};
int main(int argc, char * argv[])
{
int someInt = 1020;
#if DEMONSTRATE_ERROR_CASES
Foo<int*>().valid_if_not_pointer(&someInt);
Foo<int>().valid_if_pointer(304);
#else
Foo<int*>().valid_if_pointer(&someInt);
Foo<int>().valid_if_not_pointer(304);
#endif
return 0;
}
But if this is not broken (is it?), it's certainly not following a good general methodology for how to turn on and off methods in a templated class based on sniffing the type for traits. Is there a better solution?
Firstly, C++11 did not carry forward boost's disable_if. So if you're going to transition boost code, you'll need to use enable_if with a negated condition (or redefine your own disable_if construct).
Secondly, for SFINAE to reach in and apply to the method level, those methods must be templates themselves. Yet your tests have to be done against those templates' parameters...so code like enable_if<is_pointer<T> will not work. You can finesse this by making some template argument (let's say X) default to be equal to T, and then throw in a static assertion that the caller has not explicitly specialized it to something else.
This means that instead of writing:
template <typename T>
struct Foo {
typename enable_if<is_pointer<T>::value, void>::type
valid_if_pointer(T) const { /* ... */ }
typename disable_if<is_pointer<T>::value, void>::type
valid_if_not_pointer(T) const { /* ... */ }
};
...you would write:
template <typename T>
struct Foo {
template <typename X=T>
typename enable_if<is_pointer<X>::value, void>::type
valid_if_pointer(T) const {
static_assert(is_same<X,T>::value, "can't explicitly specialize");
/* ... */
}
template <typename X=T>
typename enable_if<not is_pointer<X>::value, void>::type
valid_if_not_pointer(T) const {
static_assert(is_same<X,T>::value, "can't explicitly specialize");
/* ... */
}
};
Both are now templates and the enable_if uses the template parameter X, rather than T which is for the whole class. It's specifically about the substitution that happens whilst creating the candidate set for overload resolution--in your initial version there's no template substitution happening during the overload resolution.
Note that the static assert is there to preserve the intent of the original problem, and prevent someone being able to compile things like:
Foo<int>().valid_if_pointer<int*>(someInt);
The way I see it you don't want SFINAE here. SFINAE is useful to pick between different templated overloads. Basically, you use it to help the compiler pick between template <typename Pointer> void f(Pointer); and template <typename NotPointer> void f(NotPointer);.
That's not what you want here. Here, you have two functions with different names, not two overloads of the same. The compiler can already pick between template <typename Pointer> void f(Pointer); and template <typename NotPointer> void g(NotPointer);.
I'll give an example to explain why I think SFINAE is not only unnecessary, but undesirable here.
Foo<int> not_pointer;
Foo<int*> pointer;
not_pointer.valid_if_pointer(); // #1
not_pointer.valid_if_not_pointer(); // #2
pointer.valid_if_pointer(); // #3
pointer.valid_if_not_pointer(); // #4
Now, let's say you managed to get this working with SFINAE. Attempting to compile this piece of code will yield errors on lines #1 and #4. Those errors will be something along the lines of "member not found" or similar. It may even list the function as a discarded candidate in overload resolution.
Now, let's say you didn't do this with SFINAE, but with static_assert instead. Like this:
template <typename T>
struct Foo {
void valid_if_pointer(T) const {
static_assert(std::is_pointer<T>::value, "valid_if_pointer only works for pointers");
// blah blah implementation
}
void valid_if_not_pointer(T) const {
static_assert(!std::is_pointer<T>::value, "valid_if_not_pointer only works for non-pointers");
// blah blah implementation
}
};
With this you'll get errors on the same line. But you'll get extremely short and useful errors. Something people have been asking of compiler writers for years. And it's now at your doorstep :)
You get the same thing: errors on both cases, except you get a much better one without SFINAE.
Also note that, if you didn't use static_assert at all and the implementation of the functions was only valid if given pointers or non-pointers, respectively, you would still get errors on the appropriate lines, except maybe nastier ones.
TL;DR: unless you have two actual template functions with the same name, it's preferable to use static_assert instead of SFINAE.