Compiler mistakes template argument list for < comparison - c++

I have a template function in the style:
template <int Exponent> DERIVED_TYPE pow(TYPE const x);
This function is defined inline in a template struct as a friend function:
template <ARGUMENTS>
struct unit {
typedef unit<ARGUMENTS> type;
....
template <int Exponent>
friend constexpr unit_pow_t<type, Exponent> pow(type const x) { ... }
};
This is because taking a value with a unit to a power has to change the unit along with the value.
When I try to use it omitting the Exponent, I can see the candidates the compiler considers for matching:
src/model/Tool.cpp:113:3: error: no matching function for call to 'pow'
pow(1._m);
^~~
src/model/../units/Units.hpp:2266:46: note: candidate template ignored: couldn't infer template argument 'Exponent'
friend constexpr unit_pow_t<type, Exponent> pow(type const x) {
^
/usr/include/math.h:255:8: note: candidate function not viable: requires 2 arguments, but 1 was provided
double pow(double, double);
^
So far things are as expected, the template is seen, but of course the Exponent needs to be specified. When I do however something unexpected happens:
src/model/Tool.cpp:113:6: error: comparison between pointer and integer ('double (*)(double, double)' and 'int')
pow<3>(1._m);
~~~^~
The compiler sees pow as the address of "double pow(double, double)" and interprets <3 as the intent to compare the function pointer with the integer. The problem occurs with clang 3.4, 3.6 and GCC 5.2.
My question is, how do I convince the compiler that <3> is a template argument list?
UPDATE
I finally managed to create a minimal example, sorry for the incomplete question:
template <int Exp>
struct metre {
double value;
template <int Exponent>
friend constexpr metre<Exp * Exponent> pow(metre<Exp> const x) {
return {0};
}
};
int main() {
pow<2>(metre<1>{1});
return 0;
};
It seems it is not seeing pow:
targs.cpp:11:2: error: use of undeclared identifier 'pow'
pow<2>(metre<1>{1});
^
If I include cmath I have the same diagnostics as before:
targs.cpp:13:5: error: comparison between pointer and integer ('double (*)(double, double)' and 'int')
pow<2>(metre<1>{1});
~~~^~
1 error generated.
So the presence of "double pow(double, double)" just masks the issue that the template is not seen. The question then is, why is pow<>() not seen by the compiler?

There is no need (and no logic) for the friend template. Use a free function:
template <int Exp>
struct metre {
double value;
};
template<int B, int A>
constexpr auto pow(metre<A> const x) -> metre<A*B>
{
return metre<A*B>{x.value};
}
int main() {
metre<2> result = pow<2>(metre<1>{1});
return 0;
};
Live demo on coliru.

This is the template friends problem, with two quirks: the name of the function being pow; and the template friend has its own template parameter!
As a rule of thumb, be on guard whenever you use friend inside a class template.
To get the easier problem out of the way first: as posted, in the MCVE, the class definition of metre doesn't cause a name pow to be declared (this will be explained later). Your error message is coming because there is in fact a visible declaration of a name pow: it's in the C standard library header math.h. The "pointer" in the error message is a function pointer to this function.
It's a good idea to not name your function the same as a function in the C standard library. Those may be defined as preprocessor macros anyway, causing further trouble.
For the rest of this post I will assume the MCVE has pow swapped out for pok , to avoid this wrinkle. Then a sane error message is generated:
po.cc:13:5: error: 'pok' was not declared in this scope
pok<2>(metre<1>{1});
^
Moving onto the main issue now.
The basic version of the problem is discussed here. The issue is that declaring a friend function inside a class template does NOT make the friend function also be a template function with the same parameter as the class template.
In fact, what happens is that for each instantiation of the class template, the friend declaration declares a non-template friend for that instantiation.
To see this in action, in your MCVE, add the line metre<1> m; as the first line of main. This instantiates metre<1>, which causes template<int Exponent> pok(metre<1>) to exist, and so the compiler recognizes pok on the next line!
In fact, any particular instantiation works, not just metre<1>, because this at least allows name lookup of pok to succeed, and then by the time overload resolution occurs (two-phase lookup!) , the argument metre<1> has caused metre<1> to be instantiated.
Closing note: I'm not entirely sure the above explanation is correct - template friends are pretty complicated. Maybe it'll turn out that actually pok is supposed to be declared and the compiler is bugged. But I concur with rubenvb's suggestion that it is best to avoid this situation entirely by not using a friend.

With the help of the previous answers I figured out a workaround.
The problem is that the friends are defined (more or less as expected) but not known outside of class/struct scope. So the compiler does not find them.
The solution is to put a declaration outside of the struct:
template <int Exp>
struct metre {
double value;
template <int Exponent>
friend constexpr metre<Exp * Exponent> pow(metre<Exp> const x) {
return {23};
}
};
template <class> void pow(); // <== HERE BE DRAGONS
int main() {
static_assert(pow<2>(metre<1>{1}).value == 23, "foobar");
return 0;
};
Note that it is not necessary to provide a matching declaration. Any template declaration for a function with the right name seems to allow the compiler to discover the friend template function.

Related

Function template argument deduction (class vs funtion template)

Could you help me understand why the argument deduction works for the class template and does not work for the function template?
If I understand correctly, the class template defines a function, so when I call it is possible for the compiler to make an implicit cast, but in case of the function template, there is no function definition at the moment, so implicit cast not happening.
But I don't understand why the compiler can't create function definition and then apply implicit cast?
#include <functional>
template<typename ...ARGS>
class Test1
{
public:
void add(const std::function<void(ARGS...)>&) {}
};
class Test2
{
public:
template<typename ...ARGS>
void add(const std::function<void(ARGS...)>&) {}
};
void func(int) {}
int main()
{
Test1<int> test1;
test1.add(func);
Test2 test2;
test2.add<int>(func);
}
The error is:
In function 'int main()':
25:24: error: no matching function for call to 'Test2::add(void (&)(int))'
25:24: note: candidate is:
14:10: note: template void Test2::add(const std::function&)
14:10: note: template argument deduction/substitution failed:
25:24: note: mismatched types 'const std::function' and 'void(int)'
In the first case, you are explicitly instantiating the class template Test1. This means the function declaration for its add member is generated with the signature add(const std::function<void(int)>&). When the compiler subsequently tries to resolve test1.add(func), there is only that one candidate. Since std::function<void(int)> can be implicitly constructed from a void(int) function, the signatures match, the compiler just instantiates the member function definition and everything is good.
In the second case, the compiler has to perform template argument deduction/substitution to see if it can "use" the add template. You may think that specifying int would nail down the template parameters so that no deduction is necessary, but that is not the case: It could be that you mean to partially specify template arguments, see for example here. In other words, you might be trying to instantiate the function template with more parameters than you specified explicitly, at least the compiler doesn't know if you do. So it still has to try and match the types of std::function<void(ARGS...)> (or more precisely, std::function<void(int, ...)> and void(int), which it can't, because implicit conversions are not considered for the deduction.
In short: Specifying explicit template arguments does not prevent template parameter deduction for variadic function templates.
Note: I am not 100% firm with the exact terminology, any language lawyering to correct me is appreciated!
Edit: I am basing this primarily on what I read here.
My original reasoning for why the following snippets work was wrong, but as #NathanOliver helped me out (see below), here is the revised explanation: During template argument deduction, no type conversions are performed. Passing a function pointer to a function that takes a std::function argument requires such a conversion. To circumvent this issue, you can call the method like this
test2.add(std::function<void(int)>(func));
or adjust the definition of Test2 to
class Test2
{
template<typename ...ARGS>
void add(void(*)(ARGS...)) {}
}
which works together with the original call
test2.add<int>(func);
In both examples, no conversion is necessary. The call to Test1::add worked out because the template type deduction has been performed before calling the method, hence the conversion could take place.
Note also that the same issue arises when Test2 is declared with one single template parameter,
class Test2
{
template<typename T>
void add(const std::function<void(T)>&) {}
}
with the following uses cases on the caller's side:
test2.add<int>(func); // Conversion ok, function template specified
test2.add(std::function<void(int)>(func)); // Type deduction, no conversion
test2.add(func); // Error, conversion AND type deduction

Why is this declaration of a function in template class invalid?

Consider the following code:
template<int X, int Y>
struct S
{
typedef int func(int,float) const;
};
template<int X>
struct D : public S<X,6>
{
typename S<X,6>::func func;
};
template<int X>
int D<X>::func(int,float) const
{
return 1;
}
//----------------
struct W : public S<7,8>
{
S<7,8>::func func;
};
int W::func(int,float) const
{
return 2;
}
#include <iostream>
int main()
{
W w;
std::cout << w.func(1,4.3) << "\n";
D<3> d;
std::cout << d.func(1,4.3) << "\n";
}
If I comment out the code declaring class D and D::func() as well as the corresponding lines in main(), the code compiles normally, and I see 2 in output, as expected.
But when I make the derived class template (adding typename before function declaration, as S<X.6> is a dependent scope), I get the following errors:
test.cpp:13:27: error: no ‘int D<X>::func(int, float) const’ member function declared in class ‘D<X>’
int D<X>::func(int,float) const
^
test.cpp: In instantiation of ‘struct D<3>’:
test.cpp:32:10: required from here
test.cpp:10:27: error: field ‘D<3>::func’ invalidly declared function type
typename S<X,6>::func func;
^
Why can't I declare func in a template derived class, while in non-template class it's OK?
What exactly is "invalidly declared function type"? what is invalid here?
N3337 [dcl.fct]/10: A typedef of function type may be used to declare a function but shall not be used to define a function.
By this rule, both D and W are technically well-formed. I think the reason this doesn't compile with GCC or Clang is that declaring a function with a typedef is really rare. Declaring a function with a member typedef dependent on a template parameter is even rarer. Looks like you've just hit on a dark corner where compiler support is limited.
Funnily enough, MSVC actually does the right thing here.
Your best option is probably to find a different way to express your classes. I can't really give any directed advice without knowing more about the problem you are trying to solve, but if you ask a new question with details we can give some suggestions.
You might also think about filing a bug report for GCC and Clang.
Edit:
However, as Jarod42 pointed out, the dependent type could later be defined as something other than a function type, making the declaration invalid. The reason MSVC works where GCC and Clang does not is the same reason MSVC doesn't require typename in some places: it doesn't correctly implement two-phase lookup. Having this case fully specified would require something like function_typename to mark a dependent name as being a function type. I think declaring a function based on a dependent type is underspecified and inconsistent as a result of this being a very rare case.
As the error message states : In D func is not a member function, thus you cannot provide a definition for it. It is a member with type S<X,6>::func.

Can we mention datatypes rather than typename and class keyword in function template definitions?

Can we mention datatypes rather than just typename and class keywords inside the angular brackets?
template <typename var, int m> // why not generate the error here itself
void c(var x){
int i = 2;
}
template void c<int, int> (int); // error: no match for any template declaration
Why do not the compiler generate error at the function template definition, when I dont use typename or class
I guess the error must not be generated because the typenames are matched, var is of int and m is already defined int. The error must be possible only if compiler ignores <int m> in the definition. but when it ignores, why not simply generate the error like not a valid code Could anyone explain me Is this compiler issue or any other reason
You defined a template with one "type" parameter and one "value" parameter. This is perfectly correct, but to use it you have to give a type and a value (which is of type int), like so: c<AnyType,5>(...);
Look for example here http://en.cppreference.com/w/cpp/language/template_parameters
An example of such thing is std::array<> from STL (in C++11) - http://en.cppreference.com/w/cpp/container/array
Because that's valid - read about non-type template parameters. What's not valid is the explicit instantiation - the second argument needs to be a value, not a type. E.g.:
template void c<int, 42> (int);

C++ Templates with function declaration/ protype and definition

I'm new to templates, was reading up on them and found a great video tutorial on them.
Furthermore, I know that there are two types of templates, class and function templates. However, in my snippet of code I only wanted to use a function template instead of a class template, but I wanted to have a function declaration and definition that makes use of the template. It seems a little weird to have the same code for the template in the function definition and declaration (I read a thread on this on the cpp website, but I can only post two links right now).
Is this the correct syntax for using a template with a function declaration and definition?
A.
Here is the snippet of consolidated code:
class GetReadFile {
public:
// Function Declaration
template <size_t R, size_t C> // Template same as definition
bool writeHistory(double writeArray[R][C], string path);
};
// Function Definition
template <size_t R, size_t C> // Template same as declaration
bool GetReadFile::writeHistory(double writeArray[R][C], string path){...}
If you're calling it the right way, the syntax works well for me:
GetReadFile grf;
double array[5][8];
grf.writeHistory<5,8>(array,"blah");
See live demo.
Note though:
Simply calling that method without specifying the actual array dimensions, these can't be automatically deduced by the compiler:
grf.writeHistory(array,"blah");
Fails with
main.cpp:24:34: error: no matching function for call to 'GetReadFile::writeHistory(double [5][8], const char [5])'
grf.writeHistory(array,"blah");
^
...
main.cpp:10:10: note: template argument deduction/substitution failed:
main.cpp:24:34: note: couldn't deduce template parameter 'R'
grf.writeHistory(array,"blah");
See the alternate demo.

Is it safe to place definition of specialization of template member function (withOUT default body) in source file?

Here's what I mean:
// test.h
class cls
{
public:
template< typename T >
void f( T t );
};
-
// test.cpp
template<>
void cls::f( const char* )
{
}
-
// main.cpp
int main()
{
cls c;
double x = .0;
c.f( x ); // gives EXPECTED undefined reference (linker error)
const char* asd = "ads";
c.f( asd ); // works as expected, NO errors
return 0;
}
This is completely fine, right?
I started doubting this, because I just ran over the specialization of '...' after instantiation error, which was new to me. So, I "worked around" this error and everything seems to work fine now, but still..
Is this well-defined behavior?
edit: And the same for non-member template functions (forward declared non-member template functions).
Lightness Races in Orbit cited why it's not compliant parts from the Standard. There might be some others, in the vicinity.
I will try to explain in simpler terms what the Standard verbiage means, and hopefully I'll get it correctly, and finally explain the linker errors (or absence of error):
What is the point of instantiation ?
How does the compiler select a specialization ?
What is necessary at the point of instantiation ?
Why a linker error ?
1/ What is the point of instantiation ?
The point of instantiation of a template function is the point where it is called or referred to (&std::sort<Iterator>) with all the template parameters fleshed out (*).
template <typename T>
void foo(T) { std::cout << typeid(T).name() << "\n"; }
int main() { foo(1); } // point of instantiation of "foo<int>(int)"
It can be delayed though, and thus not match the exact call site, for templates called from other templates:
template <typename T>
void foo(T) { std::cout << typeid(T).name() << "\n"; }
template <typename T>
void bar(T t) { foo(t); } // not a point of instantiation, T is still "abstract"
int main() { foo(1); } // point of instantiation of "bar<int>(int)"
// and ALSO of "foo<int>(int)"
This delay is very important as it enables writing:
co-recursive templates (ie, templates that refer to each-others)
user-specializations
(*) Roughly speaking, there are exceptions such as non-template methods of a template class...
2/ How does the compiler select a specialization ?
At the point of instantiation, a compiler need to be able to:
decide which base template function to call
and possibly, which of its specializations to call
This old GotW shows off the woes of specializations... but in short:
template <typename T> void foo(T); // 1
template <typename T> void foo(T*); // 2
are overloads, and each spawns a distinct family of possible specializations of which they are the base.
template <> void foo<int>(int);
is a specialization of 1, and
template <> void foo<int*>(int*);
is a specialization of 2.
In order to resolve the function call, the compiler will first pick the best overload, while ignoring template specializations, and then, if it picked a template function, check if it has any specialization that could better apply.
3/ What is necessary at the point of instantiation ?
So, from the way a compiler resolve the call, we understand why the Standard specifies that any specialization should be declared before its first point of instantiation. Otherwise, it simply would not be considered.
Thus, at the point of instantiation, one needs to have already seen:
a declaration of the base template function to be used
a declaration of the specialization to be selected, if any
But what of the definition ?
It is not needed. The compiler assumes it will either be provided later on in the TU or by another TU entirely.
Note: it does burden the compiler because it means it needs to remember all the implicit instantiations it encountered and for which it could not emit a function-body so that when it finally encounters the definition it can (at last) emit all the necessary code fo all the specializations it encountered. I wonder why this particular approach was selected, and also wonder why even in the absence of an extern declaration the TU may end with undefined function-bodies.
4/ Why a linker error ?
Since no definition is provided, gcc trusts you to provide it later and simply emits a call to an unresolved symbol. If you happen to link with another TU that provides this symbol, then everything will be fine, and otherwise you'll get a linker error.
Since gcc follows the Itanium ABI we can simply look up how it mangles the symbols. It turns out that the ABI makes no difference in mangling specializations and implicit instantiations thus
cls.f( asd );
calls _ZN3cls1fIPKcEEvT_ (which demangles as void cls::f<char const*>(char const*)) and the specialization:
template<>
void cls::f( const char* )
{
}
also produces _ZN3cls1fIPKcEEvT_.
Note: it is not clear to me whether an explicit specialization could have been given a different mangling.
No, I don't think it's okay:
[C++11: 14/6]: A function template, member function of a class template, or static data member of a class template shall be defined in every translation unit in which it is implicitly instantiated (14.7.1) unless the corresponding specialization is explicitly instantiated (14.7.2) in some translation unit; no diagnostic is required.
[C++11: 14.7.3/6]: If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. [..]
Frankly I can't explain why it works for you.
I think that your original code was incorrect and your "workaround" is not standard-compliant, too (despite the fact that your compiler and linker process it). Good quotes from the standard were cited in the answer of #Lightness Races in Orbit. See also the following example from the standard ([temp.expl.spec] 14.7.3/6):
class String { };
template<class T> class Array { /* ... */ };
template<class T> void sort(Array<T>& v) { /* ... */ }
void f(Array<String>& v) {
sort(v); // use primary template
// sort(Array<T>&), T is String
}
template<> void sort<String>(Array<String>& v); // error: specialization
// after use of primary template
template<> void sort<>(Array<char*>& v); // OK: sort<char*> not yet used
I marked my answer as community wiki because in fact it is only a big comment.