Template instantiation in GNU C++ and Clang - c++

Looks like the rules for template instantiation in Clang (3.8) and GNU C++ (4.9) are not the same. Here is an example:
#include <cstddef>
template <bool>
class Assert {
Assert(); // private constructor for Assert<false>
};
template <>
class Assert<true> { // implicit public constructor for Assert<true>
};
template <size_t N>
class A {
};
template <class T, size_t N>
T foo(A<N>) {
return T(N - 1);
}
template <class T>
T foo(A<0>) { // foo is not defined for N=0
Assert<false>();
return T(0);
}
int main(int argc, char **argv) {
foo<int>(A<3>());
return 0;
}
This minimal example shows a template function, foo, that is generalized over a type T and a natural number N. This function is not defined for N=0, so I'd like to use the Assert class to signal a compiler error if it is used this way.
This code is accepted by the GNU compiler (and by Visual C++ 2015, as well), but Clang gives an error for "calling a private constructor of class Assert<false>".
So who is right? As I see it, there is no call for foo<T,0>, so there is no need to instantiate this template...
EDIT: Accepting Clang's interpretation of the standard, what is a canonical way to enforce compile-time checks on template parameters?

I believe clang is correct, since Assert<false> is not a dependent type.
http://en.cppreference.com/w/cpp/language/dependent_name
Non-dependent names are looked up and bound at the point of template definition. This binding holds even if at the point of template instantiation there is a better match:
Don't make specializations that cannot be valid. Make them general purpose and use static_assert (with a dependent value) to check for invalid template argument types/values. static_assert(std::is_same<T, int>::value) or static_assert(N != 0)

Accepting Clang's interpretation of the standard, what is a canonical way to enforce compile-time checks on template parameters?
You can drop the "specialization"/overload of foo() for A<0> and define the general template as follows:
template <class T, size_t N>
T foo(A<N>) {
Assert<N != 0>();
return T(N - 1);
}
With C++11 you don't need to define your own static Assert and can use the language provided static_assert:
template <class T, size_t N>
T foo(A<N>) {
static_assert(N!=0, "N must be positive");
return T(N - 1);
}

Both compilers are correct. As usual, this is controlled by [temp.res]/8:
Knowing which names are type names allows the syntax of every template
to be checked. The program is ill-formed, no diagnostic required, if:
no valid specialization can be generated for a template or a substatement of a constexpr if statement ([stmt.if]) within a
template and the template is not instantiated, or
every valid specialization of a variadic template requires an empty template parameter pack, or
a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend
on a template parameter, or
the interpretation of such a construct in the hypothetical instantiation is different from the interpretation of the
corresponding construct in any actual instantiation of the template.
Your template runs afoul of the third bullet point.
As to the correct solution, either a suitable static_assert can be used, or you can explicitly delete the undesirable overload:
template <class T>
T foo(A<0>) = delete;
The former allows better error messages, the latter plays more nicely with other metaprogramming.

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.

C++20 NTTP specialization

There is disagreement between gcc/clang and msvc when trying to compile the following code:
struct foo {
};
// primary template
template<auto>
struct nttp {
static constexpr int specializaion = 0;
};
// specialization
template<foo f>
struct nttp<f> {
static constexpr int specializaion = 1;
};
int main() {
// Does not compile with msvc 19.30
nttp<5> x{};
}
Full example here.
Msvc is complaining that there is no viable conversion from int to foo which is obviously true, but shouldn't be of any relevance here as far as I understand the rules of partial template specialization.
Quoting cppreference:
When a class or variable (since C++14) template is instantiated, and there are partial specializations available, the compiler has to decide if the primary template is going to be used or one of its partial specializations.
If only one specialization matches the template arguments, that specialization is used
If more than one specialization matches, partial order rules are used to determine which specialization is more specialized. The most specialized specialization is used, if it is unique (if it is not unique, the program cannot be compiled)
If no specializations match, the primary template is used
I'd argue that there is no matching spezialization for int in this case hence the primary template should be selected.
Interestingly, the situation can be fixed by constraining the auto in the specialization by a concept:
template<class T>
concept Foo = std::is_same_v<T, foo>;
template<auto>
struct nttp {
static constexpr int specializaion = 0;
};
template<Foo auto f>
struct nttp<f> {
static constexpr int specializaion = 2;
};
// compiles with all compilers
static_assert(nttp<5>{}.specializaion == 0);
Function templates work as expected, too:
constexpr int test(auto) {
return 0;
}
constexpr int test(foo) {
return 1;
}
// compiles with all compilers
static_assert(test(5) == 0);
Long story short: empirically and intuitively I'd say that this is a bug in MSVC, but as always there's a chance that UB is involved here. So the question would be: are clang/gcc correct, or MSVC, or even all of them?
This is open MSVC bug report:
Specialization of class template with auto parameter fails to compile for an unclear reason
Your program is well-formed as per [temp.class.spec.match]/2 and [temp.class.spec.match]/3:
/2 A partial specialization matches a given actual template argument
list if the template arguments of the partial specialization can be
deduced from the actual template argument list, and the deduced
template arguments satisfy the associated constraints of the partial
specialization, if any.
/3 If the template arguments of a partial specialization cannot be
deduced because of the structure of its template-parameter-list and
the template-id, the program is ill-formed.
/3 was specifically updated as part of P0127R2 (Declaring non-type template parameters with auto), which re-wrote the previously revised wording from the resolution of CWG1315
(After CWG1315, before P0123R2) /3 Each template-parameter shall appear at least once in the template-id outside a non-deduced context.
This re-write was done particularly to allow partial specialization over non-template parameters declared with the auto placeholder type.

Conditionally enabled member functions in C++17

Suppose types can have Foo, Bar, Baz methods, and we have type traits to check it. E.g. for Foo we have HasFoo:
template <class Type>
constexpr bool DetectFoo (decltype (std::declval<Type> ().Foo ())*) { return true; }
template <class Type>
constexpr bool DetectFoo (...) { return false; }
template <class Type>
constexpr bool HasFoo = DetectFoo<Type> (nullptr);
Let's write a Wrapper<Type> class template, that forwards the property of Type having or not having these methods. For any Type the following should be satisfied:
Wrapper<Type> w; should compile, since we did not call the methods yet.
w.X (); should compile iff HasX<Type>, for X = Foo, Bar, Baz.
HasX<Wrapper<Type>> == HasX<Type> should hold, for X = Foo, Bar, Baz.
To conditionally enable a method in Wrapper there is a clear way in C++20:
template <class Type>
struct Wrapper {
void Foo ()
requires HasFoo<Type>;
};
But what to do in earlier C++ standards, without concepts? I have come up with the following idea (see live demo):
template <class Type>
struct Wrapper {
template <bool dummy = true, class = std::enable_if_t<HasFoo<Type> && dummy>>
void Foo ();
};
This answer says it is ill-formed, NDR, but I don't understand the explanation. Is this really ill-formed, NDR?
Your code is well-formed.
The linked answer refers to [temp.res.general]/8.1:
The validity of a template may be checked prior to any instantiation. ... The program is ill-formed, no diagnostic required, if:
— no valid specialization can be generated for a template ... and the template is not instantiated, ...
Here, the "template" that we're talking about is Foo.
I believe this can be interpreted in two ways:
(1) We can consider Wrapper<A>::Foo and Wrapper<B>::Foo to be the same template (for every A,B). Then, the existence of such a template argument for Wrapper that makes the condition in enable_if_t true is alone enough to make the code well-formed.
(2) We can also consider Wrapper<A>::Foo and Wrapper<B>::Foo to be different templates (for A != B). Then, if there existed such a template argument for Wrapper for which it's impossible to instantiate Foo, your code would be ill-formed NDR. But it never happens, because you can always specialize HasFoo to be true for every template argument!
In any case, I argue that (1) is the intended interpretation. The purpose of [temp.res.general]/8.1 is not to get in your way, but to help you by validating templates early when possible. I've never seen compilers use the second interpretation.

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.

Infinite recursive template instantiation expected?

I am trying to understand why a piece of template metaprogramming is not generating an infinite recursion. I tried to reduce the test case as much as possible, but there's still a bit of setup involved, so bear with me :)
The setup is the following. I have a generic function foo(T) which delegates the implementation to a generic functor called foo_impl via its call operator, like this:
template <typename T, typename = void>
struct foo_impl {};
template <typename T>
inline auto foo(T x) -> decltype(foo_impl<T>{}(x))
{
return foo_impl<T>{}(x);
}
foo() uses decltype trailing return type for SFINAE purposes. The default implementation of foo_impl does not define any call operator. Next, I have a type-trait that detects whether foo() can be called with an argument of type T:
template <typename T>
struct has_foo
{
struct yes {};
struct no {};
template <typename T1>
static auto test(T1 x) -> decltype(foo(x),void(),yes{});
static no test(...);
static const bool value = std::is_same<yes,decltype(test(std::declval<T>()))>::value;
};
This is just the classic implementation of a type trait via expression SFINAE:
has_foo<T>::value will be true if a valid foo_impl specialisation exists for T, false otherwise. Finally, I have two specialisations of the the implementation functor for integral types and for floating-point types:
template <typename T>
struct foo_impl<T,typename std::enable_if<std::is_integral<T>::value>::type>
{
void operator()(T) {}
};
template <typename T>
struct foo_impl<T,typename std::enable_if<has_foo<unsigned>::value && std::is_floating_point<T>::value>::type>
{
void operator()(T) {}
};
In the last foo_impl specialisation, the one for floating-point types, I have added the extra condition that foo() must be available for the type unsigned (has_foo<unsigned>::value).
What I don't understand is why the compilers (GCC & clang both) accept the following code:
int main()
{
foo(1.23);
}
In my understanding, when foo(1.23) is called the following should happen:
the specialisation of foo_impl for integral types is discarded because 1.23 is not integral, so only the second specialisation of foo_impl is considered;
the enabling condition for the second specialisation of foo_impl contains has_foo<unsigned>::value, that is, the compiler needs to check if foo() can be called on type unsigned;
in order to check if foo() can be called on type unsigned, the compiler needs again to select a specialisation of foo_impl among the two available;
at this point, in the enabling condition for the second specialisation of foo_impl the compiler encounters again the condition has_foo<unsigned>::value.
GOTO 3.
However, it seems like the code is happily accepted both by GCC 5.4 and Clang 3.8. See here: http://ideone.com/XClvYT
I would like to understand what is going on here. Am I misunderstanding something and the recursion is blocked by some other effect? Or maybe am I triggering some sort of undefined/implementation defined behaviour?
has_foo<unsigned>::value is a non-dependent expression, so it immediately triggers instantiation of has_foo<unsigned> (even if the corresponding specialization is never used).
The relevant rules are [temp.point]/1:
For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization and the context from which it is referenced depends on a template parameter, the point of instantiation of the specialization is the point of instantiation of the enclosing specialization. Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.
(note that we're in the non-dependent case here), and [temp.res]/8:
The program is
ill-formed, no diagnostic required, if:
- [...]
- a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter, or
- the interpretation of such a construct in the hypothetical instantiation is different from the interpretation of the corresponding construct in any actual instantiation of the template.
These rules are intended to give the implementation freedom to instantiate has_foo<unsigned> at the point where it appears in the above example, and to give it the same semantics as if it had been instantiated there. (Note that the rules here are actually subtly wrong: the point of instantiation for an entity referenced by the declaration of another entity actually must immediately precede that entity rather than immediately following it. This has been reported as a core issue, but it's not on the issues list yet as the list hasn't been updated for a while.)
As a consequence, the point of instantiation of has_foo within the floating-point partial specialization occurs before the point of declaration of that specialization, which is after the > of the partial specialization per [basic.scope.pdecl]/3:
The point of declaration for a class or class template first declared by a class-specifier is immediately after the identifier or simple-template-id (if any) in its class-head (Clause 9).
Therefore, when the call to foo from has_foo<unsigned> looks up the partial specializatios of foo_impl, it does not find the floating-point specialization at all.
A couple of other notes about your example:
1) Use of cast-to-void in comma operator:
static auto test(T1 x) -> decltype(foo(x),void(),yes{});
This is a bad pattern. operator, lookup is still performed for a comma operator where one of its operands is of class or enumeration type (even though it can never succeed). This can result in ADL being performed [implementations are permitted but not required to skip this], which triggers the instantiation of all associated classes of the return type of foo (in particular, if foo returns unique_ptr<X<T>>, this can trigger the instantiation of X<T> and may render the program ill-formed if that instantiation doesn't work from this translation unit). You should prefer to cast all operands of a comma operator of user-defined type to void:
static auto test(T1 x) -> decltype(void(foo(x)),yes{});
2) SFINAE idiom:
template <typename T1>
static auto test(T1 x) -> decltype(void(foo(x)),yes{});
static no test(...);
static const bool value = std::is_same<yes,decltype(test(std::declval<T>()))>::value;
This is not a correct SFINAE pattern in the general case. There are a few problems here:
if T is a type that cannot be passed as an argument, such as void, you trigger a hard error instead of value evaluating to false as intended
if T is a type to which a reference cannot be formed, you again trigger a hard error
you check whether foo can be applied to an lvalue of type remove_reference<T> even if T is an rvalue reference
A better solution is to put the entire check into the yes version of test instead of splitting the declval portion into value:
template <typename T1>
static auto test(int) -> decltype(void(foo(std::declval<T1>())),yes{});
template <typename>
static no test(...);
static const bool value = std::is_same<yes,decltype(test<T>(0))>::value;
This approach also more naturally extends to a ranked set of options:
// elsewhere
template<int N> struct rank : rank<N-1> {};
template<> struct rank<0> {};
template <typename T1>
static no test(rank<2>, std::enable_if_t<std::is_same<T1, double>::value>* = nullptr);
template <typename T1>
static yes test(rank<1>, decltype(foo(std::declval<T1>()))* = nullptr);
template <typename T1>
static no test(rank<0>);
static const bool value = std::is_same<yes,decltype(test<T>(rank<2>()))>::value;
Finally, your type trait will evaluate faster and use less memory at compile time if you move the above declarations of test outside the definition of has_foo (perhaps into some helper class or namespace); that way, they do not need to be redundantly instantiated once for each use of has_foo.
It's not actually UB. But it really shows you how TMP is complex...
The reason this doesn't infinitely recurse is because of completeness.
template <typename T>
struct foo_impl<T,typename std::enable_if<std::is_integral<T>::value>::type>
{
void operator()(T) {}
};
// has_foo here
template <typename T>
struct foo_impl<T,typename std::enable_if<has_foo<unsigned>::value && std::is_floating_point<T>::value>::type>
{
void operator()(T) {}
};
When you call foo(3.14);, you instantiate has_foo<float>. That in turn SFINAEs on foo_impl.
The first one is enabled if is_integral. Obviously, this fails.
The second foo_impl<float> is now considered. Trying to instantiate it, the compiles sees has_foo<unsigned>::value.
Back to instantiating foo_impl: foo_impl<unsigned>!
The first foo_impl<unsigned> is a match.
The second one is considered. The enable_if contains has_foo<unsigned> - the one the compiler is already trying to instantiate.
Since it's currently being instantiated, it's incomplete, and this specialization is not considered.
Recursion stops, has_foo<unsigned>::value is true, and your code snippet works!
So, you want to know how it comes down to it in the standard? Okay.
[14.7.1/1] If a class template has been declared, but not defined, at the point of instantiation ([temp.point]), the instantiation yields an incomplete class type.
(incomplete)