Clang does not notice default template parameters - c++

Background
According to the C++ standard, when forward-declaring a template type with default template parameters, each of them can appear in one declaration only. For example:
// GOOD example
template <class T = void>
class Example; // forward-declaration
template <class T>
class Example {}; // definition
// GOOD example
template <class T>
class Example; // forward-declaration
template <class T = void>
class Example {}; // definition
// BAD example
template <class T = void>
class Example; // forward-declaration
template <class T = void> // ERROR: template parameter redefines default argument
class Example {}; // definition
Problem
In my code I have a lot of forward declaration in different files, so it makes sense to put my default parameters in the definition:
// foo.hpp, bar.hpp, baz.hpp, etc.
template <class T>
class Example;
// example.hpp
template <class T = void>
class Example {};
and, as expected, it all works well everywhere... except clang! I narrowed the problem down to this:
In clang, if the class template has default parameters, but they are not declared in the first forward declaration of that class, and when declaring an instance of that class no angle brackets are specified, clang ignores the default parameter and raises an error "no viable constructor or deduction guide for deduction of template arguments of ...".
Example
// GOOD example
template <class T>
class Example;
template <class T = void>
class Example {};
int main() {
Example e; // error: no viable constructor or deduction guide for deduction of template arguments of 'Example'
}
Moving = void to the forward declaration fixes the issue, but is not viable for me since my forward-decls are in different files and I don't know which one will appear first. (Also super problematic since my defaults would be in some obscure file deep in the codebase)
Changing Example e; to Example<> e; fixes the issue, but is not viable for me since I'm a library dev and don't want all my users typing <> after my classes.
Adding a forward-declaration file example_fwd.hpp with one forward-declaration and including it instead of forward declaring every time fixes the issue, but I would like to avoid this if there is a better solution.
Question
Who is right in this case: clang or the other compilers? Is this a compiler bug? How can I circumvent this issue (apart from partial solutions I described above)?
I've found #10147 (and related stackoverflow questions), but it's about template template params and also is marked as fixed over a year ago.
Edit
This looks like a bug, and is now reported on LLVM bugtracker (#40488).

I don't know who's right but...
How can I circumvent this issue (apart from partial solutions I described above)?
What about adding the following deduction rule?
Example() -> Example<>;
The following code compile (C++17, obviously) with both g++ and clang++
template <class T>
class Example;
template <class T = void>
class Example {};
Example() -> Example<>;
int main() {
Example e;
}

Considering the following:
[temp.param]/12 - The set of default template-arguments available for use is obtained by merging the default arguments from all prior declarations of the template in the same way default function arguments are [ 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 ]
The default arguments available for
template <class T>
class Example;
template <class T = void>
class Example {};
will be the defaults arguments in the definition of Example. The two declarations above will be equivalent to have a single declaration as
template <class T = void>
class Example {};
which will effectively allow doing Example e.
The original code should be accepted. As a workaround and already suggested in max66's answer, you can provide a deduction guide that uses the default argument
Example() -> Example<>;

The standard does not make distinction whether a default template argument is defined in the definition or a declaration of a template.
Because Clang accepts the code when the default argument appears in the declaration, but not in the definition, at least one of this two behaviors is wrong. Considering [over.match.class.deduct]/1.1.1:
The template parameters are the template parameters of C followed by the template parameters (including default template arguments) of the constructor, if any.
, I am tempted to say that Clang should use the default template argument.
I think that you could avoid this bug by following a common practice:
If a declaration must be forwarded, create a dedicated header file for this forward declaration.
Define default arguments in this forward declaration file
Also include this file in the header file that provides the definition of the template.
As an example see iosfwd: libstdc++/iosfwd

Related

MSVC fails to deduce template argument for std::vector<std::reference_wrapper<const T>> [duplicate]

I'd like to ask whether the following code sample should compile:
#include <iostream>
#include <vector>
#include <typeinfo>
using namespace std;
template <template <class...> class C>
struct convert_container
{
using type = C<double>;
// Visual Studio requires this to be:
// using type = C<double, std::allocator<doble>>
};
int main()
{
std::cout << typeid(convert_container<std::vector>::type).name();
}
The code compiles fine with GCC 4.8.1 and Clang 3.4 but not with Visual Studio 2013. The error I get:
error C2976: 'std::vector' : too few template arguments
c:\program files (x86)\microsoft visual studio 12.0\vc\include\vector(650) : see declaration of 'std::vector'
c:\users\michał\documents\visual studio 2013\projects\transform\transform.cpp(14) : see reference to class template instantiation 'convert_container<std::vector>' being compiled
What does the standard say about this? Am I required to explicitly state all the parameters (including defaulted ones) when using the template template parameter C or is this just a bug in VC++?
Context: The issue araised from Constructor's answer to my previous question: https://stackoverflow.com/a/23874768/2617356
When searching the archives I've found this question: Default values in templates with template arguments ( C++ ) It's basically about the same problem, the question author states that default parameters for template template parameter "had to be" explicitly stated. However, the asker accepted solution that's not quite applicable in my case. The question was not about what is the standard-conforming behaviour, so I believe this is not a duplicate.
Consider the similar
template <typename = void, int = 0> struct A { };
template <template <typename ...> class T> struct B : T<> { };
template class B<A>;
This is clearly covered by the standard (14.3.3p3 if you're interested, I won't quote it, as GCC and clang do both implement the rule already), where the use of A as a template argument for B is disallowed because of the non-type template parameter. That rule makes no sense if the instantiation of a template template parameter could make use of the template template argument's default template arguments, so the behaviour of MSVC and Intel is more consistent than that of GCC and clang.
Of course, the reasoning "if this were valid, the standard would have inconsistencies" doesn't actually mean it isn't valid, only that it shouldn't be valid. To actually check what the standard says:
14.1 Template parameters [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).
8.3.6 Default arguments [dcl.fct.default]
4 Declarations in different scopes have completely distinct sets of default arguments. That is, declarations in inner scopes do not acquire default arguments from declarations in outer scopes, and vice versa.
Although not specifically intended to address this use of default template arguments, I think it does manage to do so. Nikos Athanasiou has already included the part of the standard that says any default template arguments of C do get used:
14.1 Template parameters [temp.param]
14 A template-parameter of a template template-parameter is permitted to have a default template-argument. When such default arguments are specified, they apply to the template template-parameter in the scope of the template template-parameter.
Since C's default template arguments are used, std::vector's aren't, and MSVC and Intel seem to be correct here.
And to come up with an example that clearly shows that GCC and clang cannot be considered to conform here:
template <typename = char, typename = short>
struct A { };
template <template <typename = void, typename ...> class T>
struct B {
using type = T<>;
};
Both GCC and clang treat B<A>::type as A<void, short>, taking one default template argument from T, and another from A, even though the standard disallows merging of default arguments (and hence default template arguments) in declarations in different scopes.
A workaround for you, to avoid the need to type out the allocator argument, could be to use a template alias:
template <template <class...> class C>
struct convert_container
{
using type = C<double>;
};
template <typename T>
using vector_default_alloc = std::vector<T>;
int main()
{
std::cout << typeid(convert_container<vector_default_alloc>::type).name();
}
I cannot test on MSVC right now, but Intel accepts it, and I see no reason why this variant would be invalid.
A (seemingly related) quote from the standard 14.1 Template parameters
14 . A template-parameter of a template template-parameter is permitted to have a default template-argument. When such default arguments are specified, they apply to the template template-parameter in the scope of the template template-parameter.
[ Example:
template <class T = float> struct B {};
template <template <class TT = float> class T> struct A {
inline void f();
inline void g();
};
template <template <class TT> class T> void A<T>::f() { // (*)
T<> t; // error - TT has no default template argument
}
template <template <class TT = char> class T> void A<T>::g() {
T<> t; // OK - T<char>
}
— end example ]
This is the only verse posing limitations to the use of default template parameters of template template parameters (verse 9,11,12 pose limitations on the definition/specification)
As stressed in the comments, OP's case does not involve a default parameter in convert_container (so the above does not apply explicitly). IMHO there are two ways of interpreting the situation :
using type = C<double> is a type alias for a class template; that class "loses" the right to use default template parameters, since it's passed as a template template parameter and all default arguments (of that TT parameter) lie outside the scope of the "typedefing". Then VS is correct.
By tracking the instantiation process : Say a correct compiler instantiates the struct as so (it's just a type substitution - no actual representation of the actual instantiation process is implied)
struct convert_container
{
using type = vector<double>;
};
then OP's case seems fairly legit (and gcc/clang are correct)
FWIW
This compiles in VS2013
template <template <class...> class C>
using tt = C<double>;
int main()
{
std::cout << typeid(tt<std::vector>).name();
}
So the arguments of default template parameters being non legal to pass to template template parameters seems more and more shaky.

How can I give two compatible names to a C++ class template with deduction guides?

If I have a widely-used class template called Foo that I want to rename to Bar without having to update all of its users atomically, then up until C++17 I could simply use a type alias:
template <typename T>
class Bar {
public:
// Create a Bar from a T value.
explicit Bar(T value);
};
// An older name for this class, for compatibility with callers that haven't
// yet been updated.
template <typename T>
using Foo = Bar<T>;
This is very useful when working in a large, distributed codebase. However as of C++17 this seems to be broken by class template argument deduction guides. For example, if this line exists:
template <typename T>
explicit Foo(T) -> Foo<T>;
then the obvious thing to do when renaming the class is to change the Foos in the deduction guide to Bars:
template <typename T>
explicit Bar(T) -> Bar<T>;
But now the expression Foo(17) in a random caller, which used to be legal, is an error:
test.cc:42:21: error: alias template 'Foo' requires template arguments; argument deduction only allowed for class templates
static_cast<void>(Foo(17));
^
test.cc:34:1: note: template is declared here
using Foo = Bar<T>;
^
Is there any easy and general way to give a class with deduction guides two simultaneous names in a fully compatible way? The best I can think of is defining the class's public API twice under two names, with conversion operators, but this is far from easy and general.
Your problem is exactly what P1814R0: Wording for Class Template Argument Deduction for Alias Templates
wants to solve, that is to say, in C++20, you only need to add deduction guides for Bar to make the following program well-formed:
template <typename T>
class Bar {
public:
// Create a Bar from a T value.
explicit Bar(T value);
};
// An older name for this class, for compatibility with callers that haven't
// yet been updated.
template <typename T>
using Foo = Bar<T>;
template <typename T>
explicit Bar(T) -> Bar<T>;
int main() {
Bar bar(42);
Foo foo(42); // well-formed
}
Demo.
But since it is a C++20 feature, there is currently no solution in C++17.
Have you tried to define a macro?
#define Foo Bar;
(Personally I'd find it confusing with multiple names for same implementation, but I'm not you.)
Sorry I can't test at the moment, but I hope it works!

Questions about class template argument deduction in C++17

I'm trying to make sense of P0091r3 (the "template argument deduction for class templates" paper that has been adopted into the current C++ draft standard, N4606).
I believe I understand how it works in the simplest possible case, where the template-name identifies a single template:
template<class T>
struct S {
S(T);
S(const std::vector<T>&);
};
int main()
{
std::vector<int> v;
auto s = S(v);
}
S identifies the primary template, so we create a fictitious overload set consisting of
template<class T> void Sctor(T);
template<class T> void Sctor(const std::vector<T>&);
and perform overload resolution on the fictitious call
Sctor(v)
to determine that in this case we want to call the fictitious Sctor(const std::vector<T>&) [with T=int]. Which means we end up calling S<int>::S(const std::vector<int>&) and everything works great.
What I don't understand is how this is supposed to work in the presence of partial specializations.
template<class T>
struct S {
S(T);
};
template<class T>
struct S<std::list<T>> {
S(const std::vector<T>&);
};
int main()
{
std::vector<int> v;
auto s = S(v);
}
What we intuitively want here is a call to S<std::list<int>>::S(const std::vector<int>&). Is that what we actually get, though? and where is this specified?
Basically I don't intuitively understand what P0091r3 means by "the class template designated by the template-name": does that mean the primary template, or does it include all partial specializations and explicit full specializations as well?
(I also don't understand how P0091r3's changes to §7.1.6.2p2 don't break code using injected-class-names such as
template<class T>
struct iterator {
iterator& operator++(int) {
iterator result = *this; // injected-class-name or placeholder?
//...
}
};
but that's a different question altogether.)
Are class template deduction and explicit deduction guides supported in any extant version of Clang or GCC (possibly under an -f flag, like -fconcepts is)? If so, I could play around with some of these examples in real life and probably clear up half of my confusion.
This is somewhat skated over by the proposal, but I think the intent is that only constructors of the primary class template are considered. Evidence for this is that the new [class.template.deduction] has:
For each constructor of the class template designated by the template-name, a function template with the following properties is a candidate: [...]
If we're talking about "the" class template, then this is the primary class template, particularly as class template partial specializations are not found by name lookup ([temp.class.spec]/6). This is also how the prototype implementation (see below) appears to behave.
Within the paper, class template partial specializations are contemplated in the section "Pros and cons of implicit deduction guides", but rather out of concern that constructors within the main class template could trigger a hard (non-SFINAE) error:
template<class T> struct X {
using ty = T::type;
static auto foo() { return typename T::type{} };
X(ty); #1
X(decltype(foo())); #2
X(T);
};
template<class T>
struct X<T*> {
X(...);
};
X x{(int *)0};
Your plea for class template partial specialization constructors to be considered is on the face of it reasonable, but note that it could result in ambiguity:
template<class T> struct Y { Y(T*); };
template<class T> struct Y<T*> { Y(T*); };
Y y{(int*) 0};
It would probably be desirable for the implicitly generated deduction guides to be ranked (as a tie-breaker) by specialization of the class template.
If you want to try out a prototype implementation, the authors have published their branch of clang on github: https://github.com/faisalv/clang/tree/clang-ctor-deduction.
Discussion in the paper ("A note on injected class names") indicates that injected-class-names take priority over template names; wording is added to ensure this:
The template-name shall name a class template that is not an injected-class-name.
I would say that the wording of P0091 as it currently stands is under-specified in this regard. It does need to make it clear whether it is just the primary class template or whether it includes the constructors of all specializations.
That being said, I believe that the intent of P0091 is that partial specializations do not participate in argument deduction. The feature is to allow the compiler to decide what a class's template arguments are. However, what selects a partial specialization is what those template arguments actually are. The way to get the S<std::list<T>> specialization is to use a std::list in the template argument list of S.
If you want to cause a specific parameter to use a specific specialization, you should use a deduction guide. That is what they're for, after all.

Error when using template class as template template-parameter in member variable

I am using templates in my C++ project, and I'm having an issue when using a templated type as a template template-parameter. I think the best way to describe it is to give an example that produces the error:
template <template<class> class P, typename T>
class Foo {
P<T> baz;
};
template <class T>
class Bar {
Foo<Bar, T> memberFoo;
void makeFoo() {
Foo<Bar, T>* f = new Foo<Bar, T>();
}
};
Foo<Bar, int> globalFoo;
The declaration of globalFoo causes no error, but the declarations of memberFoo and f cause the compiler error:
error: template argument for template template parameter must be a class template
or type alias template
The error only occurs when using Bar as a template parameter inside of the declaration of the Bar class, but occurs using both clang and g++. This seems like something that would be documented somewhere, but googling yields no SO questions or other documentation.
Is this use of templates simply not legal in C++, or am I misunderstanding something about how to define and use templates? If this design architecture is not allowed by the C++11 standard, what is a workaround I can use?
The issue is that an incomplete type is yielded at time of instantiation. Clang and G++ yield different errors because Clang (apparently) doesn't implement a C++11 rule that the injected class name can refer to the class template itself when used as a template template parameter (Igor's suggestion doesn't work btw.) Changing Bar to ::Bar fixes this error, which makes Clang point out the incomplete error like G++ does. Changing baz to P<T>* allows it to compile.
N.B. Even though it compiles, it probably is undefined behavior. I suggest redesigning your classes.
Based on #Igor 's comment, I have figured out a couple of workarounds for this issue. Are based on the fact that referencing Bar within its declaration refers to this specialization of Bar (to quote #Igor).
Note that all of these workarounds rely on the fact that baz can be declared as a pointer. baz not being a pointer causes a recursion issue that was mentioned by #Nir in the comments and leads to the error:
field has incomplete type 'Foo<Bar<int>, int>'
Workaround 1
Add a forward declaration of Bar and create a template alias Bar2. For this to compile, baz must be a pointer:
template <template <typename> class P, typename T>
class Foo {
P<T>* baz;
};
template<typename T> class Bar;
template <typename U> using Bar2 = Bar<U>;
template <class T>
class Bar {
Foo<Bar2, T> memberFoo;
void makeFoo() {
Foo<Bar2, T>* f = new Foo<Bar2, T>();
}
};
Foo<Bar, int> globalFoo;
The forward declaration and use of a template alias forces the compiler to use the unspecialized version of Bar when defining memberFoo and f, whereas it defaults to using the unspecialized version in the definition of globalFoo.
Workaround 2
This workaround is based on #user5800314's answer. I feel no need to re-state his workaround, but I do feel that it is worth noting the reason why it works.
I have read a similar SO question about injected class names and C++11, but the important difference here is that my code does not compile on g++, whereas theirs does. I do not believe that the issue is a lack of implementation of injected class names. I believe that this workaround fixes the compilation error because using ::Bar instead of Bar again forces the compiler to access the global (unspecialized) version of Bar instead of accessing the local (specialized) version of Bar.
Workaround 3
Specify Foo as having a class (or typename) template-parameter instead of a template template-parameter, and be explicit about which specialization is being used whenever using the Foo template. This also requires that baz is a pointer, and that it does not use a template type:
template <class P, typename T>
class Foo {
P* baz;
};
template <class T>
class Bar {
Foo<Bar, T> memberFoo;
void makeFoo() {
Foo<Bar, T>* f = new Foo<Bar, T>();
}
};
Foo<Bar<int>, int> globalFoo;
This workaround resolves the of potential confusion of template template-parameters by requiring that a specific class is provided to the Foo template. This workaround may not be usable in some cases, but may be an elegant solution in others. In my case, for instance, I will not need to instantiate an instance of Foo from outside of Bar, so this is a very nice way of getting around the compile error.
P.S. I really would like to credit #user5800314, since his workaround does work, however I provide a different explanation here, and since the explanation I provide here is what I believe is correct, I don't feel that I can mark #user5800314 's answer as accepted.

Is it required to explicitly list default parameters when using template template parameter?

I'd like to ask whether the following code sample should compile:
#include <iostream>
#include <vector>
#include <typeinfo>
using namespace std;
template <template <class...> class C>
struct convert_container
{
using type = C<double>;
// Visual Studio requires this to be:
// using type = C<double, std::allocator<doble>>
};
int main()
{
std::cout << typeid(convert_container<std::vector>::type).name();
}
The code compiles fine with GCC 4.8.1 and Clang 3.4 but not with Visual Studio 2013. The error I get:
error C2976: 'std::vector' : too few template arguments
c:\program files (x86)\microsoft visual studio 12.0\vc\include\vector(650) : see declaration of 'std::vector'
c:\users\michał\documents\visual studio 2013\projects\transform\transform.cpp(14) : see reference to class template instantiation 'convert_container<std::vector>' being compiled
What does the standard say about this? Am I required to explicitly state all the parameters (including defaulted ones) when using the template template parameter C or is this just a bug in VC++?
Context: The issue araised from Constructor's answer to my previous question: https://stackoverflow.com/a/23874768/2617356
When searching the archives I've found this question: Default values in templates with template arguments ( C++ ) It's basically about the same problem, the question author states that default parameters for template template parameter "had to be" explicitly stated. However, the asker accepted solution that's not quite applicable in my case. The question was not about what is the standard-conforming behaviour, so I believe this is not a duplicate.
Consider the similar
template <typename = void, int = 0> struct A { };
template <template <typename ...> class T> struct B : T<> { };
template class B<A>;
This is clearly covered by the standard (14.3.3p3 if you're interested, I won't quote it, as GCC and clang do both implement the rule already), where the use of A as a template argument for B is disallowed because of the non-type template parameter. That rule makes no sense if the instantiation of a template template parameter could make use of the template template argument's default template arguments, so the behaviour of MSVC and Intel is more consistent than that of GCC and clang.
Of course, the reasoning "if this were valid, the standard would have inconsistencies" doesn't actually mean it isn't valid, only that it shouldn't be valid. To actually check what the standard says:
14.1 Template parameters [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).
8.3.6 Default arguments [dcl.fct.default]
4 Declarations in different scopes have completely distinct sets of default arguments. That is, declarations in inner scopes do not acquire default arguments from declarations in outer scopes, and vice versa.
Although not specifically intended to address this use of default template arguments, I think it does manage to do so. Nikos Athanasiou has already included the part of the standard that says any default template arguments of C do get used:
14.1 Template parameters [temp.param]
14 A template-parameter of a template template-parameter is permitted to have a default template-argument. When such default arguments are specified, they apply to the template template-parameter in the scope of the template template-parameter.
Since C's default template arguments are used, std::vector's aren't, and MSVC and Intel seem to be correct here.
And to come up with an example that clearly shows that GCC and clang cannot be considered to conform here:
template <typename = char, typename = short>
struct A { };
template <template <typename = void, typename ...> class T>
struct B {
using type = T<>;
};
Both GCC and clang treat B<A>::type as A<void, short>, taking one default template argument from T, and another from A, even though the standard disallows merging of default arguments (and hence default template arguments) in declarations in different scopes.
A workaround for you, to avoid the need to type out the allocator argument, could be to use a template alias:
template <template <class...> class C>
struct convert_container
{
using type = C<double>;
};
template <typename T>
using vector_default_alloc = std::vector<T>;
int main()
{
std::cout << typeid(convert_container<vector_default_alloc>::type).name();
}
I cannot test on MSVC right now, but Intel accepts it, and I see no reason why this variant would be invalid.
A (seemingly related) quote from the standard 14.1 Template parameters
14 . A template-parameter of a template template-parameter is permitted to have a default template-argument. When such default arguments are specified, they apply to the template template-parameter in the scope of the template template-parameter.
[ Example:
template <class T = float> struct B {};
template <template <class TT = float> class T> struct A {
inline void f();
inline void g();
};
template <template <class TT> class T> void A<T>::f() { // (*)
T<> t; // error - TT has no default template argument
}
template <template <class TT = char> class T> void A<T>::g() {
T<> t; // OK - T<char>
}
— end example ]
This is the only verse posing limitations to the use of default template parameters of template template parameters (verse 9,11,12 pose limitations on the definition/specification)
As stressed in the comments, OP's case does not involve a default parameter in convert_container (so the above does not apply explicitly). IMHO there are two ways of interpreting the situation :
using type = C<double> is a type alias for a class template; that class "loses" the right to use default template parameters, since it's passed as a template template parameter and all default arguments (of that TT parameter) lie outside the scope of the "typedefing". Then VS is correct.
By tracking the instantiation process : Say a correct compiler instantiates the struct as so (it's just a type substitution - no actual representation of the actual instantiation process is implied)
struct convert_container
{
using type = vector<double>;
};
then OP's case seems fairly legit (and gcc/clang are correct)
FWIW
This compiles in VS2013
template <template <class...> class C>
using tt = C<double>;
int main()
{
std::cout << typeid(tt<std::vector>).name();
}
So the arguments of default template parameters being non legal to pass to template template parameters seems more and more shaky.