Variadic template constructor speciliazation in template class - c++

I want to be able to specialize the ctor of a class the following way:
template<typename T>
class Foo {
public:
template<typename... Ts>
Foo(Ts... & args) {
// ...
}
template<>
Foo(int i) {
// ...
}
};
I get the following error:
error: explicit specialization in non-namespace scope ‘class Foo’
If I try to move the specialization outside the class, like this:
template<typename T>
class Foo {
public:
template<typename... Ts>
Foo(Ts &... args) {
// ...
}
};
template<typename T>
template<int>
Foo<T>::Foo(int i) {
// ...
}
I get the following errors:
error: prototype for ‘Foo::Foo(int)’ does not match any in class
‘Foo’
error: candidate is: template template
Foo::Foo(Ts& ...)
How do I do this correctly?

You can just overload the constructor instead:
template<typename T>
class Foo {
public:
template<typename... Ts>
Foo(Ts&... args) {
// ...
}
// template<> <- REMOVE THIS
Foo(int i) {
// ...
}
};
Overload resolution will prefer the non-template overload so doing Foo<MyType> f(1234); would choose Foo<MyType>::Foo(int);.
LIVE EXAMPLE (I've modified the variadic to be const for it to accept temporaries for the sake of the example).
Note that the position of the type modifier in your variadic function is wrong. It should be with the type, on the left side of ...:
Foo(Ts&... args)

member function and by extension constructors are not specialize-able without specializing the outer template completely.
Just write the ctor with an int not template will works here.
14.7.3p18: "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."

Related

C++ member template specialization syntax

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

Excluding conversion operator from class template ...<typename T> based on traits on T

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?

Partial specialization of variadic template member function

I'm struggling with specializations of member functions when they are templated using variadic template.
The following example specializes a whole class and it works fine:
template<typename... Args>
class C;
template<class T, typename... Args>
class C<T, Args...> { };
template<>
class C<> { };
int main() {
C<int, double> c{};
}
The following one does not, even though the idea behind it is exactly the same of the one above:
class F {
template<typename... Args>
void f();
};
template<class T, typename... Args>
void F::f<T, Args...>() { }
int main() {
}
I'm getting the following error and I don't understand what it's due to:
main.cpp:7:23: error: non-type partial specialization ‘f<T, Args ...>’ is not allowed
void F::f<T, Args...>() { }
^
main.cpp:7:6: error: prototype for ‘void F::f()’ does not match any in class ‘F’
void F::f<T, Args...>() { }
^
main.cpp:3:10: error: candidate is: template<class ... Args> void F::f()
void f();
^
Is there some constraints I'm not aware of when specializing function template?
G++ version is: g++ (Debian 5.2.1-23) 5.2.1 20151028
EDIT
By the way, the actual problem I'm getting from the real code is:
non-class, non-variable partial specialization ‘executeCommand<T, Args ...>’ is not allowed
Anyway, the reduced example is similar to the real one. I hope the errors are not completely unrelated.
You cannot partially specialize function templates; only explicit specialization is allowed.
You can get pretty much the same effect using overloading, especially if you use concepts such as tag dispatching.

clang++ error on late default template parameter declaration

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 ]

... used without template parameters error

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