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.
Related
I am trying to make some file streamer that can read or write different types. Everything works except for the reading part with specific method. That method returns std::unique_ptr<T> when called and is a "wrapper" for another method that returns T. For some reason compiler does not use this method instead it tries to compile it with the other method (the one that returns T). The compilation fails because of this. I've already tried to search around internet but I can not find any accurate answer. Could you please help me with this.
The two methods I have defined:
template <typename T>
T read()
{
T obj;
obj.readFromFile<T>();
return std::move(obj);
}
and
template <
typename T,
template<typename> class D,
template<typename, typename> class Container
>
typename std::enable_if_t<
std::is_same<Container<T, D<T>>, std::unique_ptr<T, D<T>>>::value,
Container<T, D<T>>
>
read()
{
return std::move(std::make_unique<T, D<T>>(readFromFile<T>()));
}
The latter method is the one that I am trying to call.
When I write something like this:
std::unique_ptr<A> AfromFile = fileStreamer.read<std::unique_ptr<A>>()
compiler tries to compile it with the first method (template <typename T> T read() {...}) and the compilation fails. I could make this work if I made unique_ptr object first and than do the copy assignment to *unique_ptr<A> object but this is no good for me because i use some macro over those two functions and I cannot make unique_ptr<A> object or object A it self prior to calling the macro. Just for info I am using Visual Studio 2015.
Is there any way to make this work without any significant modification? I also found one suggestion that basically says you have to add a pointer parameter to one function and then call it with static_cast<Obj>(nullptr) as an argument but this does not count in my example.
Thanks for your help.
Update:
I just want to make a remark that all solutions below did work for me however the easiest way to fix my problem was solution provided by Barry.
Thx again for helping me!
It seems you want partial specialization, and as partial specialization on function is not possible, you may forward to class:
template <typename T> struct helper
{
T operator() const
{
T obj;
obj.readFromFile<T>();
return obj;
}
};
template <typename T, typename D>
struct helper<std::unique_ptr<T, D>>
{
std::unique_ptr<T, D> operator() const
{
return std::make_unique<T, D>(readFromFile<T>());
}
};
template <typename T>
T read()
{
return helper<T>{}();
}
The problem is, while I understand your intent of:
std::unique_ptr<A> AfromFile = fileStreamer.read<std::unique_ptr<A>>();
You're not actually calling the function you think you are. You have two overloads of read:
template <class T> T read();
template <class T,
template<typename> class D,
template<typename, typename> class Container
> T read();
The first has one template parameter, the second has 3 (and some sfinae). But you're only calling read() with one template parameter, so the second overload - the one you want - isn't even an option.
For these cases, I like simply tag dispatching so that we can overload instead of having to specialize:
template <class T> struct tag{};
template <class T> T read() { return read(tag<T>{}); }
template <class T>
T read(tag<T> ) {
T obj;
obj.readFromFile<T>();
return obj; // <== NB: no move() here! That inhibits RVO
}
template <class T, class D>
std::unique_ptr<T, D> read(tag<std::unique_ptr<T, D>> ) {
/* unique_ptr case */
}
You cannot have two overloads of a function which only differ by return type. You must use SFINAE to make sure only one is enabled for any given template parameter.
The way you are trying to deduce the template parameters in the second overload is wrong. Currently, you have to specify T, D and ContainerType when you call the function. I sense you probably want to pass just one type and then deduce whether it is a std::unique_ptr.
You cannot call std::make_unique and specify a deleter type. You must call the std::unique_ptr constructor with a newly created object.
You don't need to explicitly move the returned std::unique_ptr.
This is one way to do what you want.
#include <memory>
#include <type_traits>
template<typename T>
T readFromFile() { return T(); }
template<typename T, typename D>
void helper(std::unique_ptr<T, D>);
template<typename T, typename = void>
struct is_unique_ptr : std::false_type {};
template<typename T>
struct is_unique_ptr<T, decltype(helper(std::declval<T>()))> : std::true_type {};
template<typename T, typename = std::enable_if_t<!is_unique_ptr<T>::value>>
T read()
{
return readFromFile<T>();
}
template<typename P, typename = std::enable_if_t<is_unique_ptr<P>::value>, typename = void>
P read()
{
using T = typename P::element_type;
return P(new T(readFromFile<T>()));
}
int main()
{
read<std::unique_ptr<int>>();
read<int>();
}
I want to define a function template:
template<typename T>
void foo(T arg)
But I want T to match only certain types. Specifically, T should derive (maybe through multiple inheritance) form a certain base class. Otherwise this template shouldn't be included in the overload set.
How can I do this?
Use SFINAE with std::is_base_of:
template <typename T,
typename = std::enable_if_t<
std::is_base_of<Foo, T>::value
>>
void foo(T arg);
That will only include foo in the overload set if T inherits from Foo. Note that this includes ambiguous and inaccessible bases as well. If you want a solution that only allows for Ts that inherit publicly and unambiguously from Foo, then you can instead use std::is_convertible:
template <typename T,
typename = std::enable_if_t<
std::is_convertible<T*, Foo*>::value
>>
void foo(T arg);
Note the reversal of arguments.
Regardless of which form you pick, it can be aliased for brevity:
template <typename T>
using enable_if_foo = std::enable_if_t<std::is_base_of<Foo, T>::value>;
template <typename T,
typename = enable_if_foo<T>>
void foo(T arg);
This works because std::enable_if has a nested type named type if and only if the boolean passed in is true. So if std::is_base_of<Foo, T>::value is true, enable_if_t gets instantiated to void, as if we had written:
template <typename T,
typename = void>
void foo(T arg);
But, if T does not inherit from Foo, then the type trait will evaluate as false, and std::enable_if_t<false> is a substitution failure - there is no typename enable_if<false>::type. You might expect this to a compile error, but substitution failure is not an error (sfinae). It's just a template deduction failure. So the effect is that foo<T> is simply removed from the set of viable overload candidates in this case, no different from any other template deduction failure.
SFINAE based techniques such as the following;
template <typename T,
typename Test = std::enable_if_t<std::is_base_of<Foo, T>::value>>
void foo(T arg);
Are good to remove the function from the overload list - which would be a general case.
If you wish to keep the function in the list, and if chosen as the best overload to fail if the type matches some criteria (such as a base requirement here), the static_assert can be used;
template <typename T>
void foo(T arg)
{
static_assert(std::is_base_of<Foo, T>::value, "failed type check");
// ...
}
In C++1z with concepts lite, you can do this:
template<class T>
requires std::is_base_of<Foo, T>{}()
void foo(T arg) {
}
under the current (experimental) implementation. Which is pretty clean and clear. There may be a way to do something like:
template<derived_from<Foo> T>
void foo(T arg) {
}
but I haven't worked it out. You can definitely do:
template<derived_from_foo T>
void foo(T arg){
}
where we have a custom concept called derived_from_foo that applies iff the type is derived from foo. What I don't know how to do is template concepts -- concepts generated from template type parameters.
In C++14, here are two methods. First, normal SFINAE:
template<class T,
class=std::enable_if_t<std::is_base_of<Foo, T>{}>
>
void foo(T arg) {
}
here we create a template that deduces the type T from its argument. It then tries to deduce its second type argument from the first argument.
The second type argument has no name (hence class=), because we are only using it for a SFINAE test.
The test is enable_if_t< condition >. enable_if_t< condition > generates the type void if condition is true. If condition is false, it fails in "the immediate context", generating a substitution failure.
SFINAE is "Substitution failure is not an error" -- if your type T generates a failure in the "immediate context" of the function template signature, this doesn't generate a compile-time error, but instead results in the function template not being considered a valid overload in this case.
"Immediate context" is a technical term here, but basically it means the error has to be "early enough" to be caught. If it requires compiling bodies of functions to find the error, that is not in "the immediate context".
Now, this isn't the only way. I personally like hiding my SFINAE code behind a gloss of respectability. Below, I use tag dispatching to "hide" the failure somewhere else, instead of putting it right up front in the function signature:
template<class T>
struct tag {
using type=T;
constexpr tag(tag const&) = default;
constexpr tag() = default;
template<class U,
class=std::enable_if_t<std::is_base_of<T,U>{}>
>
constexpr tag(tag<U>) {}
};
struct Base{};
struct Derived:Base{};
template<class T>
void foo( T t, tag<Base> = tag<T>{} ) {
}
here we create a tag dispatch type, and it allows conversion to base. tag lets us worth with types as values, and use more normal C++ operations on them (instead of template-like metaprogramming <>s all over the place).
We then give foo a second argument of type tag<Base>, then construct it with a tag<T>. This fails to compile if T is not a derived type from Base.
live example.
The nice thing about this solution is that the code that makes it not work seems more intuitive -- tag<Unrelated> cannot convert to tag<Base>. This does not, however, prevent the function from being considered for overload resolution, which can be a problem.
A way with less boiler plate is:
template<class T>
void foo( T t, Base*=(T*)0 ) {
}
where we use the fact that pointers can be converted iff there is a derivation relationship between them.
In C++11 (and without constexpr support), we first write a helper:
namespace notstd {
template<bool b, class T=void>
using enable_if_t=typename std::enable_if<b,T>::type;
}
then:
template<class T,
class=notstd::enable_if_t<std::is_base_of<Foo, T>::value>
>
void foo(T arg) {
}
if you don't like the helper, we get this ugly extra:
template<class T,
class=typename std::enable_if<std::is_base_of<Foo, T>::value>::type
>
void foo(T arg) {
}
the second C++14 technique above can also be translated to C++11.
You can write an alias that does the test if you want:
template<class U>
using base_test=notstd::enable_if_t<std::is_base_of<Base, U>::value>;
template<class T,
class=base_test<T>
>
void foo(T arg) {
}
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.
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);
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