Without using Boost, how can I write a function like:
template<typename T>
void myFunc(T t)
{
...
}
template<>
void myFunc(someclass<T> t)
{
myFunc(t.get());
}
Update: I may have over analyzed this. I was confused when I wanted the original
template<typename T>
void myFunc(T t)
{
...
}
to work with vector. I suppose I got confused because in specializations of template functions you omit the typename argument and I thought I needed the T still.
It appears one of the answers may already work.
Not sure why you associate Boost with this. Anyway:
This won't work since T doesn't exist here.
template<>
void myFunc(someclass<T> t);
What you probably meant is:
template < typename T >
void myFunc(someclass<T> t);
Related
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.
I'm using SFINAE to build a rudimentary serialization library.
Let's say I have a class that implements a generic process method, that reads in any type (allowing for user-extension) and serializes it. I'm using std::enable_if to specialize this method to different template argument types. Here's an example:
class OutputSerializer
{
public:
OutputSerializer(std::ostream& str) : stream(str) {}
private:
template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
process(T&& arg) {
stream.write(&arg, sizeof(arg));
}
//More specializations here
std::ostream& stream;
};
I want to optimize this method for booleans, by making the output stream store 1 byte, instead of sizeof(bool) bytes. Similarly to how I did before, I add a new template specialization:
class OutputSerializer
{
public:
OutputSerializer(std::ostream& str) : stream(str) {}
private:
template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
process(T&& arg) {
stream.write(&arg, sizeof(arg));
}
template<typename T>
typename std::enable_if<std::is_same<T, bool>::value, void>::type
process(T&& arg) {
stream.write(&arg, 1);
}
std::ostream& stream;
};
Now, a question arises. std::is_arithmetic<bool> is also supposed to return true. So which of the two specializations will be given priority during name resolution?
Keep in mind, this is only a theoretical question. I know of more ways to make sure this method does what I want it to, such as specializing the template itself for bool, like this:
template<>
void process<bool>(bool&& arg) {
stream.write(&arg, 1);
}
or by adding an extra check in the more generic case, like this:
template<typename T>
typename std::enable_if<
std::is_arithmetic<T>::value
&& !std::is_same<T, bool>::value, void>::type
process(T&& arg) {
stream.write(&arg, sizeof(arg));
}
Or at least, I'm pretty sure these would work. Feel free to call me out on it if I'm wrong. Thank you!
Neither has any sort of priority. Both templates will result in the function void process(bool) and the call will be ambiguous.
Example
Adding an explicit specialization for bool won't work either, since there's no clear base template to specialize. You need to add more conditions to the std::is_arithmetic version of the template, or better just provide a non-template overload for bool. Functions do have priority over function templates, so a non-template version will be chosen by overload resolution.
Example
From here on a (endo)functor is something able to take an object and transform it in another object of the same type. The simplest example of functor is the identity:
struct Identity {
template <typename T>
T Apply(T x) {
return x
}
};
I need to have a "Functor type" that identifies a generic Functor. What I would like to do is write code like:
class Sum {
public:
Sum(Functor* f, Functor* g) :
f_(f),
g_(g) {}
template <typename T>
T Apply(T x) { return f_->Apply(x) + g_->Apply(x); }
private
Functor* f_;
Functor* g_;
};
The first idea that came to my mind is of course using a virtual class:
struct Functor {
template <typename T>
virtual T Apply(T x) = 0;
};
The unsolvable problem with this approach is that templates cannot be virtual.
Then I tried using C++ concepts. But, as stated in Specifying a concept for a type that has a member function template using Concepts Lite and
C++ Concepts: Can I define a concept that is itself a template? it is not possible to have a "templated concept".
Finally I have stumbled upon How to achieve "virtual template function" in C++ and therefore I came up with the following possible implementation:
struct Functor {
template <typename T>
T Apply(const T& x); // No more virtual!!!
};
// ... Identity and Sum declarations properly inheriting from Functor ...
template <typename T>
T Functor::Apply(T x) {
if (Identity* specialized =
dynamic_cast<Identity*>(this)) {
return specialized->Apply(x);
} else if (const Sum* specialized =
dynamic_cast<const Sum*>(this)) {
return specialized->Apply(x);
} else ...
}
Even though this is compiling, it's not the best solution. The main issues are: performance and code repetition.
The performance issue comes from the fact that each time Apply is called on a Functor the long if clause inside Functor::Apply must be resolved. This is a big problem as Functor can be deeply nested (so calling Apply may result in multiple call to Functor::Apply). The "code repetition" issue is quite self evident as each time I want to define a new Functor I have also to modify Functor::Apply adding a new if clause.
What I am asking here is whether there is a proper (cleaner) way to define a Functor interface/concept that makes possible creating classes like Sum.
C++ concepts and heavy template metaprogramming is accepted.
p.s. All the code snippets have been kept as simple as possible on purpose. Avoid suggesting to use class instead of struct or to add const identifiers or to use unique pointers, it's not the point of this question.
Most of the (best) solutions I can think of unfortunately require that you adopt some fairly complex methodologies. Which isn't necessarily a bad thing, of course, but it can make things confusing as you move forward with designing a program. For that reason, I'd probably suggest something a little more straight-forward:
template <typename F, typename G>
class Sum {
public:
Sum(F& f, G& g) :
f_(f),
g_(g) {}
template <typename T>
inline T Apply(T x) { return f_.Apply(x) + g_.Apply(x); }
private:
F& f_;
G& g_;
};
/*
For every class like the above, you may want to define an
easy-to-use generating function to simplify instantiations:
*/
template <typename F, typename G>
inline Sum<F, G> MakeSum(F& f, G& g)
{
return Sum<F, G>(f, g);
}
#include <cmath>
struct SquareRoot {
template <typename T>
inline T Apply(T x)
{
return std::sqrt(x);
}
};
struct Triple {
template <typename T>
inline T Apply(T x)
{
return T(3) * x;
}
};
// Example:
#include <iostream>
int main(void)
{
using namespace std;
SquareRoot square_root;
Triple triple;
// For g++, don't forget to compile with -std=c++1z
auto sum = MakeSum(square_root, triple);
cout << sum.Apply(1024) << endl;
}
Granted, it isn't as powerful as other techniques, but it may be a good starting point nonetheless.
If I have a complicated function that I want to use for two collections with matching interfaces (at least as far as the function in question is concerned) is there a way to just re-use the template code?
For example:
void DoSomethingIntense(std::vector<blah> myBlah);
void DoSomethingIntense(std::array<blah> myBlah);
If I use begin, end, size, and other functions that both array and vector have in common, is there a way to re-use the body of DoSomethingIntense without typing it twice (or, heaven forbid, stuffing it into a macro)?
(Please do not nitpick the example code, it doesn't help anybody)
UPDATE: My apologies, I neglected to mention that the function in question has other implementations for classes that do not match this signature; just making every argument use the code that works for these two is not an option.
I think the iterator solution might be best in that scenario.
Yes, use a template.
template <typename Container>
void DoSomethingIntense(Container blah) { // Might be better as Container const &
// write code using blah.begin() or whatever
}
You might be able to make it even more generic, following the example of STL, by supporting a general iterator range rather than specifically a container:
template <typename Iterator>
void DoSomethingIntense(Iterator begin, Iterator end);
Yes, you can achieve that by using templates:
template<typename T>
void DoSomethingIntense(const T &myBlah);
EDIT:
If I get your update right then I would say make use of SFINEA:
template<typename T>
struct is_vector : std::false_type {};
template<typename T, typename A>
struct is_vector<std::vector<T, A>> : std::true_type {};
template<typename T>
struct is_array : std::false_type {};
template<typename T, size_t N>
struct is_array<std::array<T, N>> : std::true_type {};
// add more if you want or define a macro
template<typename T>
std::enable_if_t<is_vector<T>::value || is_array<T>::value, void>
DoSomethingIntense(const T &myBlah)
{
}
int main()
{
std::vector<int> v;
DoSomethingIntense(v); // OK
std::array<float, 5> a;
DoSomethingIntense(a); // OK
std::queue<int> q;
DoSomethingIntense(q); // ERROR
}
You can mix templates / overloads. No problem.
For example:
template <typename T>
void DoSomethingIntense(T myBlah) {
}
void DoSomethingIntense(MyCustomClass myBlah) {
}
Then it will use the non-template version for argument type MyCustomClass and the template version for anything else (like vector or array)
Moreover, you can use std::enable_if to restrict the range of possible template arguments. See also this question.
After reading the answer to this question, I learned that SFINAE can be used to choose between two functions based on whether the class has a certain member function. It's the equivalent of the following, just that each branch in the if statement is split into an overloaded function:
template<typename T>
void Func(T& arg)
{
if(HAS_MEMBER_FUNCTION_X(T))
arg.X();
else
//Do something else because T doesn't have X()
}
becomes
template<typename T>
void Func(T &arg, int_to_type<true>); //T has X()
template<typename T>
void Func(T &arg, int_to_type<false>); //T does not have X()
I was wondering if it was possible to extend SFINAE to do multiple rules. Something that would be the equivalent of this:
template<typename T>
void Func(T& arg)
{
if(HAS_MEMBER_FUNCTION_X(T)) //See if T has a member function X
arg.X();
else if(POINTER_DERIVED_FROM_CLASS_A(T)) //See if T is a pointer to a class derived from class A
arg->A_Function();
else if(DERIVED_FROM_CLASS_B(T)) //See if T derives from class B
arg.B_Function();
else if(IS_TEMPLATE_CLASS_C(T)) //See if T is class C<U> where U could be anything
arg.C_Function();
else if(IS_POD(T)) //See if T is a POD type
//Do something with a POD type
else
//Do something else because none of the above rules apply
}
Is something like this possible?
Thank you.
This is certainly possible; you just have to be careful to ensure that all of the branches are mutually exclusive, otherwise you'll end up with an ambiguity.
Take a look at Boost Type Traits and Boost Enable If, which are the two best tools for supporting this. Boost ICE (which stands for Integral Constant Expression) can be used to combine multiple type traits to help you to do more complex type matching (and to ensure that your overloads are mutually exclusive.
This can be somewhat complicated and convoluted, so here's a relatively straightforward example. Say you have a class hierarchy:
struct Base { };
struct Derived : Base { };
and you want to call one overload of a function foo for Base, and another overload for any class derived from Base. A first attempt might look like:
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
using namespace boost;
using namespace boost::type_traits;
template <typename T>
typename enable_if<is_same<Base, T>, void>::type
foo(const T&) { }
template <typename T>
typename enable_if<is_base_of<Base, T>, void>::type
foo(const T&) { }
However, is_base_of returns true if T is the base class, so if you attempt to call foo(Base()), there is an ambiguity because both function templates match. We can resolve this by using a combination of the type traits and using the Boost ICE helpers:
template <typename T>
typename enable_if<is_same<Base, T>, void>::type
foo(const T&) { }
template <typename T>
typename enable_if<
ice_and<
is_base_of<Base, T>::value,
ice_not<is_same<Base, T>::value>::value
>, void>::type
foo(const T&) { }
These overloads are mutually exclusive, and they ensure there is no ambiguity.
Some of your examples are not supported (namely, HAS_MEMBER_FUNCTION_X; I'm not sure about IS_TEMPLATE_CLASS_C--depending on what you want to do with it you might be able to make something work), but in general this is possible.
The question is easy when you realize that
if (a) { X(); }
else if (b) { Y(); }
means exactly the same as
if (a) { X(); }
if (!a && b) { Y(); }
However, you could also extend your true/false dichotomy.
enum FuncVariants { HasMember, PointerDerivedFromA, DerivedFromB, InstanceOfC, isPod }
template<typename T>
void Func(T &arg, int_to_type<HasMember>);
template<typename T>
void Func(T &arg, int_to_type<DerivedFromA>);
template<typename T>
void Func(T &arg, int_to_type<DerivedFromB>);
template<typename T>
void Func(T &arg, int_to_type<InstanceOfC>);
(Obviously, when calling you have to take care as the options are not mutually exclusive)
the way you have it implemented, no.
Compilation will fail if arg does not have one of the functions. (I think you know this, just making sure).
However, it is possible to do so using template specialization (hidden in magic of boost mpl).
you could do sometime this using boost mpl vector with meta-functions: check out
http://www.boost.org/doc/libs/1_40_0/libs/mpl/doc/refmanual.html
typedefs typename mpl::vector<f0,f1,...>::type handlers; // different handlers
// convert logic to int N to map condition to handler
// can use ternary or bit shift trick
// more general approach could be to use vector of mpl::bool_ and mpl::find
typedef typename mpl::vector_c<bool, (first_condition),
(second_condition),...>::type condition;
typedef typename mpl::find<condition, mpl:: bool_<true> >::type iterator;
typedef typename mpl::at<handlers, iterator::pos::value>::type handler;
handler::apply(...); // call handler with some arguments
depending on exactly requirements, you can try different approach.
Above is something have done few hours ago