List of compiler template arguments for <comparison

I have a template function in the style of:

 template <int Exponent> DERIVED_TYPE pow(TYPE const x); 

This function is defined in the string structure of the template 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 due to the fact that when using a unit value with power, you must change the device along with the value.

When I try to use it without an exponent, I see candidates that the compiler considers to match:

 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, everything has been as expected, the template is being viewed, but, of course, you must specify the exhibitor. When I do, 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 goal of comparing the function pointer with an 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 list of template arguments?

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

He doesn't seem to see pow:

 targs.cpp:11:2: error: use of undeclared identifier 'pow' pow<2>(metre<1>{1}); ^ 

If I enable 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. 

Thus, the presence of "double pow (double, double)" simply masks the problem that the template is not displayed. The question then becomes: why are pow <> () not considered by the compiler?

+5
source share
3 answers

There is no need for a friend template (and no logic). Use the 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 .

+3
source

This is a problem with friend patterns, with two quirks: function name pow ; and the familiar template has its own template parameter!

Generally, be on your guard when you use friend inside a class template.

To simplify the task in the first place: as indicated in MCVE, the definition of the metre class does not cause pow declarations (this will be explained later). Your error message comes because there is actually a visible declaration for the name pow : it is in the header of the C math.h standard library. The "pointer" in the error message is a pointer to this function.

It is a good idea not to call your function the same as the function in the standard C library. In any case, they can be defined as preprocessor macros, which causes additional problems.

For the rest of this post, I assume that MCVE has pow replaced with pok to avoid this wrinkle. Then an audio error message is generated:

 po.cc:13:5: error: 'pok' was not declared in this scope pok<2>(metre<1>{1}); ^ 

Now we turn to the main problem.

The basic version of the problem is discussed here . The problem is that declaring a friend function inside a class template does NOT make a friend function also a template function with the same parameter as the class template.

In fact, what happens is that for each instance of the class template, a friend declaration declares a non-template friend for that instance.

To see this in action, in MCVE add the line metre<1> m; as the first line of main . This creates an instance of metre<1> , which leads to the existence of template<int Exponent> pok(metre<1>) , and therefore the compiler recognizes pok on the next line!

In fact, any particular instance creation works, not just metre<1> , because it at least allows you to search for the pok name for success, and then by the time when overload resolution occurs (two-phase search!), The argument metre<1> called the instance of metre<1> .


Final note. I am not entirely sure that the above explanation is correct. Friends of the templates are pretty complicated. It may turn out that pok should actually be declared, and the compiler is listening. But I agree with Rubenvb's suggestion that it is best to avoid this situation without using friend .

+3
source

Using the previous answers, I figured out a workaround.

The problem is that friends are defined (more or less as expected), but are not known outside the scope of the class / structure. Therefore, the compiler does not find them.

The solution is to place the ad outside the structure:

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

Please note that there is no need to provide an appropriate announcement. Any template declaration for a function with the correct name appears to allow the compiler to detect a friend's template function.

0
source

Source: https://habr.com/ru/post/1237835/


All Articles