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.
Related
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'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'));
}
I have a template function, whose type depends on type parameters. The compiler can't deduce template parameter even if it's obvious. This is a basic code and even here it doesn't know it is an int (int is just example). What should be changed to make it work?
#include <iostream>
using namespace std;
template<class T1, class T2>
T1 pr (T2 w) {
return int(w);
}
int main() {
cout<<pr('A'); // your code goes here
return 0;
}
Compiler can only deduce template type arguments only from function arguments types, not from result type. To make it work without changing function template you need to explicitly specify type argument:
cout << pr<int>('A');
But it is probably better to change the definition, since T1 parameter doesn't seem to be useful:
template<class T>
int pr (T w){
return int(w);
}
In C++11 you can use trailing return type, which might be useful in more complex situations:
template<class T>
auto pr (T w) -> decltype(int(w)) {
return int(w);
}
And finally C++14 has return type deduction, so ther it is simply:
template<class T>
auto pr (T w) {
template<typename T>
Ref<Iterator<T> > GetFilterIterator(Ref<Iterator<T> > i, boost::function<bool(T)> pred) {
return new FilterIterator<T>(i, pred);
}
Ref<Iterator<CWorm*> > x = GetFilterIterator(worms(), &CWorm::getLocal);
And worms() returns a Ref<Iterator<CWorm*> Ref> and there is bool CWorm::getLocal(); (which is a member function). And:
template<typename T> struct Ref {
// ...
};
template<typename T> struct Iterator {
// ...
};
This will fail to deduce the template argument:
Iter.h:272:27: note: candidate template ignored: failed template argument deduction [3]
Why?
If I call it with the specified template argument, i.e. GetFilterIterator<CWorm*>(worms(), &CWorm::getLocal), it doesn't complain. I wonder why it cannot deduce the template argument like this. And can I make it different somehow so that it would be able to automatically deduce the type?
Do you mean typname Iterator<T>::Ref for the type of the first parameter in the GetFilterIterator template declaration? If so, that is not a deducible context for template type parameters.
Consider:
template<>
struct Iterator<Foo> {
typedef int Ref;
};
template<>
struct Iterator<Bar> {
typedef int Ref;
};
GetFilterIterator(int(0),f);
Both Iterator<Foo>::Ref and Iterator<Bar>::Ref match the parameter passed to GetFilterIterator, an int. Which one should it pick? C++ disallows deducing template types from parameters like the one you've declared.
With the update to your question it looks like you do mean ::Ref<Iterator<T> >. I think that should be deducible then, and since the typedef Iterator<CWorm*>::Ref is ::Ref<Iterator<CWorm*> > it seems like it should be able to deduce T. I'm not sure why it's not working.
The compiler cannot deduce the template arguments because fitting to the parameters would mean a non-trivial conversion - first to Iterator<T> and then to Ref<Iterator<T> > which both require user-defined conversions. Also, directly converting the member function pointer to boost::function is similarly non-trivial for the compiler.
IBM has a list of supported template parameter deductions.
If you want your template arguments to be deduced automatically, you have to provide wrapper methods:
template <typename T>
Ref<Iterator<T> > makeIteratorRef(T val) {
return Ref<Iterator<T> >(Iterator<T>(val));
}
template <typename T>
boost::function<bool (T)> makeFn(bool (T::*fn) () const) {
boost::function<bool (T)> res = boost::bind(fn, _1);
return res;
}
...
Ref<Iterator<CWorm*> > x = GetFilterIterator(makeIteratorRef(worms()), makeFn(&CWorm::getLocal));
This way the compiler is capable of deducing the template parameters because no conversions are necessary.
By the way, I think you are overcomplicating simple things:
for (auto it = worms().begin(); it != worms().end(); ++it)
if (it->isLocal()) {
// Do something
}
This code is way more readable in C++ and even though it might not be as general it hardly makes the code worse.
Thanks to the hint from Xeo to here about that implicit type conversions are not allowed when deducing template arguments, I wondered wether the second parameter might cause problems here. I thought that it would do the type deduction from left to right and once the type is deducted, it is not a problem anymore (for the function pointer to boost::function cast).
It seems I was wrong and this was exactly the problem.
Another version of the same thing avoids the problem:
template<typename T>
struct PartialFuncWrapper {
::Ref<Iterator<T> > i;
PartialFuncWrapper(::Ref<Iterator<T> > _i) : i(_i) {}
typename Iterator<T>::Ref operator()(boost::function<bool(T)> pred) {
return new FilterIterator<T>(i, pred);
}
};
template<typename T>
PartialFuncWrapper<T> GetFilterIterator(::Ref<Iterator<T> > i) {
return PartialFuncWrapper<T>(i);
}
Then I can write:
Ref<Iterator<CWorm*> > x = GetFilterIterator(worms())(&CWorm::getLocal);
This is related to my earlier post. I'd like to know why one attempted solution didn't work.
template <typename... T> /* A */
size_t num_args ();
template <>
size_t num_args <> ()
{
return 0;
}
template <typename H, typename... T> /* B */
size_t num_args ()
{
return 1 + num_args <T...> ();
}
If I try to call, say, num_args<int,float>() then the error is that the function call is ambiguous:
A with T={int,float}
B with H=int, T={float}
I don't understand how this is ambiguous -- A is a declaration and B is a definition of the function declared by A. Right?
I'm trying to make this example work and the responses to my earlier question seem to claim that it can never work.
If that's the case, what's the point of variadic free functions? What can they do?
I don't understand how this is ambiguous -- A is a declaration and B
is a definition of the function declared by A. Right?
No. A is a declaration of a function template, and B is a declaration (and definition) of another function template.
The compiler has no way to decide between the two: they both have no arguments, and the template arguments are a match for both.
The one in the middle is an explicit total specialization of the function template declared in A.
If you tried to make B another specialization of A:
template <typename H, typename... T> /* B */
size_t num_args<H, T...>()
{
return 1 + num_args <T...> ();
}
... you'd end up with a partial specialization of a function template, which is not allowed.
You can do this with the usual trick of using a class template with partial specializations and a function template that calls into the class template:
template <typename... T>
class Num_Args;
template <>
struct Num_Args <>
{
static constexpr size_t calculate() {
return 0;
}
};
template <typename H, typename... T>
struct Num_Args <H, T...>
{
static constexpr size_t calculate() {
return 1 + Num_Args<T...>::calculate();
}
};
template <typename... T> /* B */
constexpr size_t num_args ()
{
return Num_Args<T...>::calculate();
}
Apropos the usefulness/uselessness of free variadic function templates: the usual use case for these is to have a variadic function parameter list, in which case a regular overload for the empty case will do just fine:
size_t num_args()
{
return 0;
}
template <typename H, typename... T> /* B */
size_t num_args (H h, T... t)
{
return 1 + num_args(t...);
}
EDIT:
As far as I can see, the following abuse of enable_if ought to work as a solution to your original question:
#include <utility>
// Only select this overload in the empty case
template <typename... T>
typename std::enable_if<(sizeof...(T) == 0), size_t>::type
num_args()
{
return 0;
}
template <typename H, typename... T>
size_t
num_args()
{
return 1 + num_args<T...>();
}
(Edit2: Reversed the order of the overloads to make the code actually compile)
While I really like the std::enable_if<sizeof...(T) == 0, _> hack by JohannesD, I'll still drop the below hack that I don't actually remember where I learned from, which resolves the ambiguity with only free functions without having to use classes:
template <typename One>
size_t num_args() {
return 1;
}
template <typename First, typename Next, typename... Rest>
size_t num_args() {
return 1 + num_args<Next, Rest...>();
}
No partial specialization required, and it totally avoids the zero parameter case by ending the unpacking recursion at one parameter. Also, see https://stackoverflow.com/a/58295007/1525238 for an even nicer c++17 solution that uses the same idea.
The only catch is that it actually doesn't cover the zero template parameter case, which is impossible in the context of free functions AFAIK. If that is required from the consumer's perspective, a partially specialized class must be used, see R. Martinho Fernandes' answer.
As for the utility of variadic template free functions, I find them particularly useful as constexpr type-safe accumulating calculator utilities.