I must be missing something obvious here because this really came to me as a surprise.
The following code gives me the error: error: missing template arguments before ‘a’
template<int n=0>
class A {};
...
A a;
...
Is there a reason why a template with 1 parameter declared with a default value has to be instantiated specifying a value for it?
Can someone quote the standard?
A is still a template class. But you can omit the template parameter though:
template<int n=0>
class A {};
int main() {
A<> a;
// ^^
return 0;
}
See the live demo.
I think1 the relevant standard section is here
14.7 Template instantiation and specialization
...
3 An explicit specialization may be declared for a function template, a class template, a member of a class
template or a member template. An explicit specialization declaration is introduced by template<>. In
an explicit specialization declaration for a class template, a member of a class template or a class member
template, the name of the class that is explicitly specialized shall be a simple-template-id. In the explicit specialization declaration for a function template or a member function template, the name of the function
or member function explicitly specialized may be a template-id.
[Example:
template<class T = int> struct A {
static int x;
};
template<class U> void g(U) { }
template<> struct A<double> { }; // specialize for T == double
template<> struct A<> { }; // specialize for T == int
template<> void g(char) { } // specialize for U == char
// U is deduced from the parameter type
template<> void g<int>(int) { } // specialize for U == int
template<> int A<char>::x = 0; // specialize for T == char
template<class T = int> struct B {
static int x;
};
template<> int B<>::x = 1; // specialize for T == int
— end example ]
1)Sorry, I can't find a better standard cite / example. It doesn't cover exactly the OP's case, but demonstrates at least the same, that templates still need the <> angle brackets to be identified as templates (classes or functions).
possible workaround if it's important to disguise the nature of your object:
// the template class
template<int n=0>
class ReallyA {};
// an alias for the common case
using A = ReallyA<0>;
A a;
This is how the standard library defines std::string, for example.
using string = basic_string<char>;
Related
On this site there is the following paragraph:
When defining a member of an explicitly specialized class template outside the body of the class, the syntax template <> is not used, except if it's a member of an explicitly specialized member class template, which is specialized as a class template, because otherwise, the syntax would require such definition to begin with template< parameters > required by the nested template.
I do not know what the highlighted section means. Does "otherwise" refer to the general case (in which template<> is not used) or to the exception case (in which template<> must be used)?
I would appreciate an explanation of that section.
This will be our template:
template< typename T>
struct A {
struct B {}; // member class
template<class U> struct C { }; // member class template
};
See the following code:
template<> // specialization
struct A<int> {
void f(int); // member function of a specialization
};
// template<> not used for a member of a specialization
void A<int>::f(int) { /* ... */ }
We are not using template<> while defining the member of a specialization, as this is a normal member class.
But, now see the next code:
template<> // specialization of a member class template
template<class U> struct A<char>::C {
void f();
};
// template<> is used when defining a member of an explicitly
// specialized member class template specialized as a class template
template<>
template<class U> void A<char>::C<U>::f() { /* ... */ }
Here we are specializing a member template of the defined template. That is why we will need to use template<> to pass the parameters that this member template needs. In this case class U is needed for defining our member template, so for passing that we will need the keyword template<>.
This question covers C++03, and how to omit a conversion operator from a class template, say template<typename T> struct Foo { ... };, given traits on T.
(Questions at the bottom)
Background
Ideally, I'd would like to make use of an enable_if construct and SFINAE to exclude a conversion operator based on traits of T of class template (see Foo above), but default template arguments may not be used in function templates in C++03, which (afaik) excludes that approach; as previously covered in the following thread:
enable_if and conversion operator?
Instead, I'm using an approach where the type of the return value of the conversion operator is conditional on traits on T, particularly being a dummy (void or some private externally inaccessible type) for certain types of T. This approach seems to work fine, but I'm uncertain what possible pitfalls I might be digging for myself; specifically what is guaranteed by the (C++03) Standard in this context.
Consider the following example (which I've tried to keep as minimal as possible), using the approach described in the previous paragraph:
include/util.h:
namespace util {
// dummy predicate: is T int?
template <typename T> struct is_int { static const bool value = false; };
template <> struct is_int<int> { static const bool value = true; };
template <typename T> const bool is_int<T>::value;
// [meta.trans.other]/conditional
template <bool B, class T, class F> struct conditional { typedef T type; };
template <class T, class F> struct conditional<false, T, F> { typedef F type; };
// class template with non-template operator() member
template <typename T> struct Foo {
explicit Foo(const T &value) : value_(value) {}
// [Question regarding this conversion operator here]
operator typename conditional<is_int<T>::value, int, void>::type() const {
return value_;
}
private:
T value_;
};
/* Alternatively */
template <typename T> class Bar {
struct Dummy {};
T value_;
public:
explicit Bar(const T &value) : value_(value) {}
operator typename conditional<is_int<T>::value, int, Dummy>::type() const {
return value_;
}
};
} // namespace util
main.cc:
#include "include/util.h"
void baz(int) {}
int main()
{
const util::Foo<int> foo_int(42);
baz(foo_int); // OK
const util::Foo<char> foo_char('a');
const util::Bar<int> bar_int(42);
baz(bar_int); // OK
const util::Bar<char> bar_char('a');
/* OK, expected:
Error: cannot convert ‘const util::Foo<char>’/‘const util::Bar<char>’
to ‘int’ for argument ‘1’ to ‘void baz(int)
baz(foo_char);
baz(bar_char); */
return 0;
}
This compiles fine using gcc and clang (-std=c++03), but I'm wondering if it's really OK to conditionally have an invalid body(/return) for the conversion operator, as is the case e.g. for a full instantiation of Foo<char>. I'm assuming it's fine due to partial implicit instantiation; [temp.inst]/1 (14.7.1 in the C++03 standard draft) describes [emphasis mine]:
The implicit instantiation of a class template specialization causes
the implicit instantiation of the declarations, but not of the
definitions or default arguments, of the class member functions,
member classes, static data members and member templates; and it
causes the implicit instantiation of the definitions of member
anonymous unions. Unless a member of a class template or a member
template has been explicitly instantiated or explicitly specialized,
the specialization of the member is implicitly instantiated when the
specialization is referenced in a context that requires the member
definition to exist;
Question
Does the C++03 Standard guarantee that a conditionally (trait on T) invalid non-template member function body of a class template is not an error in case it is not referenced from instantiations of the class where it is/would be invalid?
According to 17.7.3 [temp.expl.spec] paragraph 5 (N4659),
... Members of an explicitly specialized class template are defined in the same manner as members of normal classes, and not using the template<> syntax. The same is true when defining a member of an explicitly specialized member class. However, template<> is used in defining a member of an explicitly specialized member class template that is specialized as a class template.
The explicit specialization of E definitely does not belong to the bold case, and it still needs template<>. Why is that?
template<class T> struct A {
enum E : T;
};
template<> enum A<int>::E : int { eint };
This paragraph is related to members of an explicitly specialized class template, but you have not explicitly specialized the class template. This is an example of the case it is talking about:
template<class T> struct A {
enum E : T;
};
template<> struct A<int> {
enum E : int;
};
enum A<int>::E : int { eint }; // no template<> here
In your example code, you have explicitly specialized a member of the primary template, which does require using template<>, as specified in the first paragraph.
1 An explicit specialization of any of the following:
...
(1.7) — member enumeration of a class template
...
can be declared by a declaration introduced by template<>; that is:
explicit-specialization:
template < > declaration
The underlying principle behind paragraph 5 is that once you've explicitly specialized a template, it is no longer a template, and you work with the specialization just like you would any other non-template entity.
The following code compiles fine with g++, but not with clang++ (3.6):
// Forward declaration:
template <class S, class T>
struct Base;
template <class T>
struct BaseFriend {
friend struct Base<int, T>;
};
// Actual declaration:
template <class S, class T = int>
struct Base {
void foo() {}
};
struct DerivedFriend : BaseFriend<int> {};
struct Derived : Base<int> {
void foo(int) {
Base<int>::foo();
}
};
Error occurs in the Derived::foo definition:
error: too few template arguments for class template 'Base'
Base<int>::foo();
^
test.cpp:3:8: note: template is declared here
struct Base;
^
Error goes away after few minor fixes, like:
If default template parameter is defined in forward declaration instead of actual declaration.
Or if DerivedFriend is not used.
But, what is wrong with the original code?
Definitely a clang bug, looks like #10147. The standard clearly allows this [temp.param]/10:
The set of default template-arguments available for use with a template declaration or definition is obtained
by merging the default arguments from the definition (if in scope) and all declarations in scope in the same
way default function arguments are (8.3.6). [ Example:
template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;
is equivalent to
template<class T1 = int, class T2 = int> class A;
—end example ]
I am in need of your help once again...
I had the following code, which was causing explicit specialization in non-namespace scope error:
namespace __test
{
template <int A, int B, typename C> class Test
{
template <int V> void check(C & a) { }
template <> void check<0>(C & a) { } //error: explicit specialization in non-namespace scope 'class __test::Test<A, B, C>'
};
}
Since I already know how to fix this kind of errors, I defined specialization outside of the class scope, however I got another error - ... used without template parameters:
namespace __test
{
template <> void Test::check<0>(C & a) { } //error: 'template<int A, int B, class C> class __test::Test' used without template parameters
}
I'm probably just being stupid, but I don't understand the cause of this problem and I don't know how to fix it... Please help!
By my reading of the standard, what you want to do appears to be legal. Quoting §14.7.3/18:
In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well. In such explicit specialization declaration, the keyword template followed by a template-parameter-list shall be provided instead of the template<> preceding the explicit specialization declaration of the member. The types of the template-parameters in the template-parameter-list shall be the same as those specified in the primary template definition.
As you're explicitly specializing a member function template rather than a class member template, it should be fine; however, neither Comeau, GCC, nor VC++ allow the following, which should be correct syntax:
namespace test
{
template<int A, int B, typename C>
class Test
{
template<int V>
void check(C& a) { }
};
template<int A, int B, typename C>
template<>
void Test<A, B, C>::check<0>(C& a) { }
}
Comeau says error: a template declaration containing a template parameter list may not be followed by an explicit specialization declaration, which makes sense if we apply the rule in §14.7.3/18 to member function templates as well
GCC says invalid explicit specialization before '>' token; enclosing class templates are not explicitly specialized, which again makes sense if we apply the rule in §14.7.3/18 to member function templates as well
VC++ says error C2768: 'test::Test<A,B,C>::check' : illegal use of explicit template arguments, which isn't a helpful error message, but generally falls in line with the others
My guess is that there must be a defect report filed that also disallows explicit specializations of member function templates when the enclosing class templates are not explicitly specialized as well; however, I can't say this definitively since the wording for §14.7.3/18 hasn't changed between the C++03 standard and the C++0x FDIS (which it would if a DR was filed against C++03 and accepted).
You need to either fully specialize everything, like this:
namespace __test {
template <int A, int B, typename C>
class Test
{
template <int V> void check(C & a) { }
};
template <>
template <>
void Test<1, 2, int>::check<0> (int &)
{
}
}
Or use a helper structure to avoid trying to partially specialize template method of a template class (which GCC and many others won't understand):
namespace __test {
template <typename C, int V>
struct TestHelper
{
static void check (C & a)
{
}
};
template <typename C>
struct TestHelper<C, 0>
{
static void check (C & a)
{
}
};
template <int A, int B, typename C>
class Test
{
template <int V> void check(C & a)
{
TestHelper<C, V>::check (a);
}
};
}