I've created the following struct:
template<class T>
struct not_equals
{
not_equals(T d):data(d){};
bool operator()(T const & in)
{
return data != in;
}
T data;
};
My expectation was that since I need to pass some value of concrete type d to the constructor, template argument T will be deduced from type of d.
However, this does not happens.
not_equals('0'); // fails with 'missing template arguments'
char zero = '0';
not_equals(zero); // same as above
not_equals<char>('0'); // compiles without errors
What is the reason for compiler not recognizing type of template argument?
c++17 will allow class template deduction
Until then, you can create a "make" function:
template <class T> auto make_not_equals(const T& d) -> not_equals<T>
{
return {d};
}
auto z = make_not_equals('0');
This is the C++03 version of the make function:
template <class T> not_equals<T> make_not_equals(const T& d)
{
return not_equals<T>(d);
}
Unfortunately when you declare a variable you need to spell the whole type with the template because of missing auto feature, but the make function can still be helpful in a deduced context, for instance for a parameter:
template <class T> void foo(not_equals<T> ne);
void test()
{
foo(make_not_equals('0'));
}
Related
I am writing a kind of container class, for which I would like to offer an apply method which evaluates a function on the content of the container.
template<typename T>
struct Foo
{
T val;
/** apply a free function */
template<typename U> Foo<U> apply(U(*fun)(const T&))
{
return Foo<U>(fun(val));
}
/** apply a member function */
template<typename U> Foo<U> apply(U (T::*fun)() const)
{
return Foo<U>((val.*fun)());
}
};
struct Bar{};
template class Foo<Bar>; // this compiles
//template class Foo<int>; // this produces an error
The last line yields error: creating pointer to member function of non-class type ‘const int’. Even though I only instantiated Foo and not used apply at all. So my question is: How can I effectively remove the second overload whenever T is a non-class type?
Note: I also tried having only one overload taking a std::function<U(const T&)>. This kinda works, because both function-pointers and member-function-pointers can be converted to std::function, but this approach effectively disables template deduction for U which makes user-code less readable.
Using std::invoke instead helps, it is much easier to implement and read
template<typename T>
struct Foo
{
T val;
template<typename U> auto apply(U&& fun)
{
return Foo<std::invoke_result_t<U, T>>{std::invoke(std::forward<U>(fun), val)};
}
};
struct Bar{};
template class Foo<Bar>;
template class Foo<int>;
However, this won't compile if the functions are overloaded
int f();
double f(const Bar&);
Foo<Bar>{}.apply(f); // Doesn't compile
The way around that is to use functors instead
Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return f(decltype(bar)(bar)); });
Which also makes it more consistent with member function calls
Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return decltype(bar)(bar).f(); });
In order to remove the second overload you'd need to make it a template and let SFINAE work, e. g. like this:
template<typename T>
struct Foo
{
T val;
//...
/** apply a member function */
template<typename U, typename ObjT>
Foo<U> apply(U (ObjT::*fun)() const)
{
return Foo<U>((val.*fun)());
}
};
Alternatively, you could remove the second overload altogether, and use lambda or std::bind:
#include <functional> // for std::bind
template<typename T>
struct Foo
{
T val;
/** apply a member function */
template<typename U, typename FuncT>
Foo<U> apply(FuncT&& f)
{
return {f(val)};
}
};
struct SomeType
{
int getFive() { return 5; }
};
int main()
{
Foo<SomeType> obj;
obj.apply<int>(std::bind(&SomeType::getFive, std::placeholders::_1));
obj.apply<int>([](SomeType& obj) { return obj.getFive(); });
}
How can I effectively remove the second overload whenever T is a non-class type?
If you can use at least C++11 (and if you tried std::function I suppose you can use it), you can use SFINAE with std::enable_if
template <typename U, typename V>
typename std::enable_if<std::is_class<V>{}
&& std::is_same<V, T>{}, Foo<U>>::type
apply(U (V::*fun)() const)
{ return Foo<U>((val.*fun)()); }
to impose that T is a class.
Observe that you can't check directly T, that is a template parameter of the class, but you have to pass through a V type, a template type of the specific method.
But you can also impose that T and V are the same type (&& std::is_same<V, T>{}).
The following code does not compile with gcc 6.4 in Debian Sid, due to the error: "typename is not allowed".
struct A
{
template <typename T,typename R> static R f(T x)
{
return (R)x;
}
};
template <class FUNCTION,typename T,typename R> R func()
{
return FUNCTION::f<T,R>(2);
}
int main()
{
return func<A,int,double>();
}
Interestingly enough the following code does compile:
struct A
{
template <typename T> static T f(T x)
{
return x;
}
};
template <class FUNCTION,typename T> T func()
{
return FUNCTION::f(2.f);
}
int main()
{
return func<A,float>();
}
I presume that the second code does compile because the argument of the function provides enough information for GCC to perform template substitution. However I do not understand why the first code fails to compile. So does anybody can explain me why?
You need to use keyword template to tell the compiler that the dependent name f (it depends on the template parameter FUNCTION) is a template name. Only when the compiler knows that's a template name it takes < as the beginning of template-argument-list, otherwise it will try to take < as the less-than operator.
e.g.
return FUNCTION::template f<T,R>(2);
// ~~~~~~~~
The 2nd one works because you didn't use <> (to specify template arguments explicitly).
I understand that a template cannot infer a type from assignment, i.e.
template <typename T>
T aFunction (int a) { /*...*/ }; // This obviously won't work
And it's pretty evident why. But this will work:
template <typename T>
T aFunction (T a, T b) { return a + b; }; // a-ok
'cause T will be inferred from the arguments. I want to kinda extrapolate from that:
template <typename T>
T aFunction (std::function<T(int)> a) { return a(3);};
^
|
I specified it! ----------
so that when used, there's no ambiguity on what the function should do:
std::function<double(int)> blah = [](int x){ return x / 2.0f; };
aFunction(blah);
Alas, the compiler won't cooperate with me:
No matching member function for call to 'aFunction'
Candidate template ignored: could not match
'function' against '(lambda at
file.hpp:274:16)'
Is there a way to make this happen?, short of template specialization (this is a very generic class), or a dummy argument (I'm not that desperate yet).
P.D.:
Full disclosure: Above was just a simplification of the problem, exactly what I need is:
template <typename T>
class MyStuff {
template <typename ReturnType>
MyStuff<ReturnType> aFunction(std::function<ReturnType(T)> a){
/*for each stuff in MyStuff do a(stuff)*/
}
}
Where MyStuff contains properties of type T and a bunch of inline functions, such as aFunction.
As mentioned in the comments, this works:
#include <functional>
template <typename T>
struct MyStuff {
template <typename ReturnType>
MyStuff<ReturnType> aFunction(std::function<ReturnType(T)> a){
return {};
}
};
int main() {
MyStuff<int> stuff;
std::function<double(int)> fn = [](int) { return 0.; };
stuff.aFunction(fn);
}
Instead this doesn't work:
int main() {
MyStuff<int> stuff;
stuff.aFunction([](int) { return 0.; });
}
And the error is the one posted in the question:
note: candidate template ignored: could not match 'function' against '(lambda at main.cpp:15:21)'
The reason is that type deduction works only for exact type. No conversions are allowed. In your case the compiler should deduce first of all the return type of the lambda, than convert it to an std::function somehow and finally deduce the return type of the function from the one constructed by using the lambda.
This is not how type deduction works.
You can work around it with something like this:
template <typename T>
struct MyStuff {
template <typename F>
auto aFunction(F &&f) -> MyStuff<decltype(std::forward<F>(f)(std::declval<T>()))> {
return {};
}
};
See it on Coliru.
I am playing around with ways to filter types passed to overloaded function templates. I'm using Visual Studio 2013.
Three part question:
Why cant my compiler deduce Blorg3?
Is the reason that TFoo2(argc) generates a compiler error the same as #1?
Is there a way to pass template parameters to a constructor?
Here is the sample code:
#include <type_traits>
#define IFPTR(T,R) typename std::enable_if<std::is_pointer<T>::value, R>::type
#define IFINT(T,R) typename std::enable_if<std::is_integral<T>::value, R>::type
template <class T, IFINT(T, T)* = nullptr> int Blorg1(T n) { return n + 1; }
template <class T, IFPTR(T, T)* = nullptr> int Blorg1(T n) { return *n + 1; }
template <class T> IFINT(T, int) Blorg2(T n) { return n + 1; }
template <class T> IFPTR(T, int) Blorg2(T n) { return *n + 1; }
template <class T> int Blorg3(IFINT(T, T) n) { return n + 1; }
template <class T> int Blorg3(IFPTR(T, T) n) { return *n + 1; }
struct TFoo1 {
template <class T, IFINT(T, T)* _ = nullptr> TFoo1(T n) { }
};
struct TFoo2 {
template <class T> TFoo2(IFINT(T, T) n) { }
};
int main(int argc, char* argv[])
{
Blorg1(argc); // intellisense not happy
Blorg2(argc);
Blorg3<int>(argc); // why cant deduce?
Blorg1(*argv); // intellisense not happy
Blorg2(*argv);
Blorg3<char*>(*argv); // why cant deduce?
(void)TFoo1(argc); // intellisense not happy
(void)TFoo2(argc); // intellisense not happy and !!wont compile!!
return 0;
}
Answer for 1/2 about the reason SFINAE isn't working:
SFINAE and template parameter deduction don't play well together in this context.
Or, they do so long as you're aware of the proper order things happen in.
The deduction must be guaranteed to work to be considered as a possible function to be called in this instance.
Here's a way to look at this in a less technical way:
The compiler searches possible function signatures that match what you're trying to call. [see overload resolution]
If it finds a template parameter, it looks to see if it's valid for deduction.
And this is why you're running into problems. The order in which these two events occur is why what SFINAE works on Blorg1, Blorg2 and TFoo1 but not Blorg3 or TFoo2.
With Blorg3 and TFoo2 the compiler can't slot the parameter you're passing to the template type as it creates a circular dependancy that can't be resolved.
template <class T> int Blorg3(IFINT(T, T) n) { return n + 1; }
template <class T> int Blorg3(IFPTR(T, T) n) { return *n + 1; }
Blorg3<char*>(*argv); // why cant deduce?
To resolve the SFINAE in Blorg3 here requires knowing T. However, T isn't known until the SFINAE is resolved.
The same goes for why TFoo2 doesn't work.
Part 3 - about templates and constructors
Yes, you can pass template parameters to constructors, but only if you do it through deduction such as what was done with TFoo1.
You cannot explicitly pass template parameters to a constructor.
Why cant my compiler deduce Blorg3?
In std::enable_if<std::is_pointer<T>::value, R>::type the ::type refers to a nested name that is dependent on the template parameters T and R. This is a non-deduced context (§14.8.2.5/5), consequently the compiler won't deduce the template argument.
Is that why TFoo2(argc) generates a compiler error?
Yes, a constructor template must be able to deduce its template arguments, and in this case it can't.
Is there a syntax to provide template parameters to a constructor?
No, as I already mentioned, you cannot do so explicitly, they must be deduced, or the template parameters must have default arguments.
I am trying to get working the thing described in the title.
template <class T>
void foo(const Foo* f) // this is general case template
{
}
// this should work only if T has static variable named _Foo with type const Foo*
template <class T>
typename std::enable_if<std::is_same<decltype(T::_Foo), const Foo*>::value>::type
foo(const Foo* f)
{
T::_Foo = f;
}
But it fails to compile with:
error C2039: 'type' : is not a member of 'std::enable_if<false,void>'
Shouldn't it default to the first implementation if enable_if fails ? I mean what am I missing here, could someone please explain to me what is wrong and possibly what is a solution. (I have a feeling that the problem lies in this naive decltype(T::_Foo))
It only works if there is a deduced template argument involved. You probably need to add a level of indirection and also disable the first method in case T does have a suitable _Foo. Or, as an alternative, I'll show how to lower its priority for overload resolution by using ... vs. int:
template <class T>
void foo_impl(const Foo* f, T*, ...) // this is general case template
{
}
// this should work only if T has static variable named _Foo with type const Foo*
template <class T>
typename std::enable_if<std::is_same<decltype(T::_Foo), const Foo*>::value>::type
foo_impl(const Foo* f, T*, int)
{
T::_Foo = f;
}
template <class T>
void foo(const Foo* f) // this is general case template
{
return foo_impl(f, (T*)nullptr, 0);
}
Live example