template parameters in templated type function - c++

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).

Related

Forward declared functions and SFINAE

I've encountered an interesting pattern in the unconstexpr library.
According to the readme, the idea is that given a forward declared auto return type function, the return type can't be deduced before the function is actually defined, and this allows some SFINAE magic.
I thought this language feature could be useful for a few other ideas, and did some experiments with it, and it looks like gcc and clang behaves differently when the function isn't a template: gcc works the same, while clang reports an error.
And based on what the error message of clang shows, maybe it shouldn't work even for a template?
So the questions are:
is the template part (allowed by both clang and gcc) allowed by the standard?
which compiler is correct about the non template version?
Simplified code (also on godbolt):
struct S {};
constexpr auto f1();
template <typename T>
constexpr auto f2(T);
// compilation error with clang:
// function with deduced return type cannot be used before it is defined
template <typename T, typename = decltype(f1())>
void test1_1() {}
template <typename T>
void test1_1() {}
// compiles with clang, even if f2 will never be defined
template <typename T, typename = decltype(f2<T>(T{}))>
constexpr int test1_2(int) { return 1; }
template <typename T>
constexpr int test1_2(float) { return 2; }
/////////////////
int g1_2() {
return test1_2<S>(0);
}
constexpr auto f1() { return 1; }
// comment-uncomment this:
// the value returned by g2_# will change
// /*
template <typename T>
constexpr auto f2(T) {
return 2;
}
// */
// can be defined here
template <typename T, typename = decltype(f1())>
void test2_1() {}
int g2_2() {
return test1_2<S>(0);
}
Note: originally I also mentioned that it behaves differently with friends, and that it seems to be working without an auto return type - those were user errors on my part.

SFINAE and template function instantiation: Why a template argument cannot be deduced when used in function arguments with a SFINAE-enabled type?

I was experimenting with SFINAE these days, and something puzzles me. Why my_type_a cannot be deduced in my_function's instantiation?
class my_type_a {};
template <typename T>
class my_common_type {
public:
constexpr static const bool valid = false;
};
template <>
class my_common_type<my_type_a> {
public:
constexpr static const bool valid = true;
using type = my_type_a;
};
template <typename T> using my_common_type_t = typename my_common_type<T>::type;
template <typename T, typename V>
void my_function(my_common_type_t<T> my_cvalue, V my_value) {}
int main(void) {
my_function(my_type_a(), 1.0);
}
G++ gives me this:
/home/flisboac/test-template-template-arg-subst.cpp: In function ‘int main()’:
/home/flisboac/test-template-template-arg-subst.cpp:21:30: error: no matching function for call to ‘my_function(my_type_a, double)’
my_function(my_type_a(), 1.0);
^
/home/flisboac/test-template-template-arg-subst.cpp:18:6: note: candidate: template<class T, class V> void my_function(my_common_type_t<T>, V)
void my_function(my_common_type_t<T> my_type, V my_value) {}
^~~~~~~~~~~
/home/flisboac/test-template-template-arg-subst.cpp:18:6: note: template argument deduction/substitution failed:
/home/flisboac/test-template-template-arg-subst.cpp:21:30: note: couldn't deduce template parameter ‘T’
my_function(my_type_a(), 1.0);
^
What I expected was that, when calling my_function as I did in main, T would be deduced to the type of the function's first argument, and that type would be used in the function's instantiation. But it seems that my_common_type_t<T> is instantiated before the function, but even then, the type of my_cvalue would become my_type_a anyways, so I cannot see why this wouldn't work...
Is there a different way to do this? Should I just avoid two (or more) levels of template indirection?
Well, consider this:
template <>
struct my_common_type<int> {
constexpr static const bool valid = true;
using type = my_type_a;
};
template <>
struct my_common_type<double> {
constexpr static const bool valid = true;
using type = my_type_a;
};
// ...
int main(void) {
my_function(my_type_a{}, 1.0);
}
Does the compiler chooses my_common_type<int> or my_common_type<double>?
If the language would permit deduction in you case, it would have to match what T would be in my_common_type<T>::type in order to yield the exact type you send to the function parameter. Obviously, it's not only impossible, but with my example above, it may have multiple choices!
Fortunately, there is a way to tell the compiler that my_common_type<T> will always yield to T. The basics of the trick is this:
template<typename T>
using test_t = T;
template<typename T>
void call(test_t<T>) {}
int main() {
call(1);
}
What is T deduces to? int, easy! The compiler is happy with this kind of match. Also, since test_t cannot be specialized, test_t<soxething> is known to only be something.
Also, this is working too with multiple levels of aliases:
template<typename T>
using test_t = T;
template<typename T>
using test2_t = test_t<T>;
template<typename T>
void call(test2_t<T>) {}
int main() {
call(1); // will also work
}
We can apply this to your case, but we will need some tool:
template<typename T, typename...>
using first_t = T;
This is the same easy match as above, but we can also send some argument that will not be used. We will make sfinae in this unused pack.
Now, rewrite my_common_type_t to still be an easy match, whilst adding the constraint in the unused pack:
template <typename T>
using my_common_type_t = first_t<T, typename my_common_type<T>::type>;
Note that this is also working:
template <typename T>
using my_common_type_t = first_t<T, std::enable_if_t<my_common_type<T>::valid>>;
Now deduction will happen as expected! Live (GCC) Live (Clang)
Note that this trick will only work with C++14, as sfinae in this case (dropped parameters) is only guaranteed to happen since C++14.
Also note that you should either use struct for your trait, or use public: to make the member my_common_type<T>::type public, or else GCC will output a bogus error.

Confused by template argument deduction

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'));
}

Template argument deduction and SFINAE - using std::enable_if

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.

g++ compiler error with templated base class member

I'm trying to compile some Microsoft Visual C++ code using g++. Now I've come across a compiler error which I really can't understand. The (simplified) code looks like this:
template<int X> struct A {
template<class Ret> static Ret call() {
return 0;
}
};
template<int X> struct B : A<X> {
int f() {
return A<X>::call<int>();
}
};
When I try to compile this with g++ (version 4.4.5), I get the following error:
main.cpp: In member function int B<X>::f():
main.cpp:16: error: expected primary-expression before int
main.cpp:16: error: expected ; before int
main.cpp:16: error: expected unqualified-id before > token
If I remove the template type (Ret) from method A::call, the code compiles just fine. Can anybody see whats wrong here?
Thanks!
You need the template keyword:
return A<X>::template call<int>();
call is a dependent name, meaning that its signification depends on a template parameter, which is not known when the compiler process f(). You need to indicate that call is a function template by prefixing it with the template keyword.
The same thing happens when you try to access a nested type: you need to add the typename keyword to indicate that the name denotes a type:
template <typename T>
struct A { typedef int type; };
template <typename T>
void f()
{
typename A<T>::type i = 0; // notice "typename" here
}
And sometimes you even need to mix both:
template <typename T>
struct A
{
template <typename U>
struct inner { };
};
template <typename T>
void f()
{
typename A<T>::template inner<int> var;
}
The use of these two keywords is thoroughly explained in the answers to this question: Where and why do I have to put the “template” and “typename” keywords? (thanks to #Björn Pollex for finding the link).
A is a template, and without knowing X the compiler can't determine the contents of A<X>. Especially it doesn't know that call will end up being a template.
To tell that to the compiler you have to use the template keyword:
template<int X> struct B : A<X> {
int f() {
return A<X>::template call<int>();
}
};
You have to specify that the function you're calling is a template, as it's part of a template class. The compiler is not aware that any given A<X> has a template function named call, and therefore you need to help it.
template<int X> struct B : A<X> {
int f() {
return A<X>::template call<int>();
}
};