Re: nested templates syntax
On 2011-06-16 09:10, Jonathan Thornburg wrote:
I have a template class fuzzy which contains a (static) template
member function make_integer. I want to call make_integer() from
a (non-class) template test . This all works fine... until I try
to pass one of test's template parameters as fuzzy's template parameter.
At this point both g++ and Comeau agree that my code is invalid.
My basic question is, why is this so?
In particular, consider the following code:
#include<cmath>
#include<limits>
#include<iostream>
template<typename fp>
class fuzzy
{
public:
// convert floating-point to integer, checking for overflow first
template<typename itype>
static itype make_integer(fp x);
};
template<typename fp>
template<typename itype>
itype fuzzy<fp>::make_integer(fp x)
{
return (std::abs(x)<= std::numeric_limits<itype>::max())
? itype(x)
: -1; // overflow flag
}
// prototype
template<typename fp, typename itype>
void test(const char* const label, const fp x);
template<typename fp, typename itype>
void test(const char* const label, const fp x)
{
const itype i = fuzzy<double>::make_integer<itype>(x); // ok
std::cout<< label<< ": x = "<< x<< " ==> i = "<< i<< "\n";
#if 1
const itype j = fuzzy<fp>::make_integer<itype>(x); // bad
std::cout<< label<< ": x = "<< x<< " ==> j = "<< j<< "\n";
#endif
}
int main()
{
test<double, int>("test<double, int>", 3.14159 );
test<double, int>("test<double, int>", 3.14159e15);
test<double, long long>("test<double, long long>", 3.14159 );
test<double, long long>("test<double, long long>", 3.14159e15);
}
Both g++ 4.2.4 and http://www.comeaucomputing.com/tryitout 4.3.10.1 Beta2
agree that the line commented "// bad" is in error. (With the "#if 1"
changed to "#if 0", g++ -W -Wall accepts the code with no warnings or
errors, and the output when running the code is what I expect.)
The only difference between the "// ok" and "// bad" lines is in the
template parameter for fuzzy .
As I outlined above, my question is, why is the "// bad" line not legal
C++? We're inside the function
template<typename fp, typename itype>
void test(const char* const label, const fp x)
so fp and itype are both known to be template parameters.
thanks for any insights anyone can provide,
14.2 p4 says:
"When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.[..]"
In your example "fuzzy<fp>" you have the third situation, this means that 'fuzzy<double>::make_integer' is assumed to be a non-template unless you explicitly specify this by adding a template prefix:
fuzzy<fp>::template make_integer<itype>(x)
This is not required for
fuzzy<double>::make_integer<itype>(x)
because is not dependent, thus the compiler can immediately recognize (even without instantiating the surrounding template) that fuzzy<double>::make_integer *is* a template.
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]