#include <tuple>
template<std::size_t... Is, std::size_t... Js>
auto test(std::tuple<std::index_sequence<Is, Js>...>) {}
int main()
{
test(std::tuple<std::index_sequence<0, 0>>{});
}
You can see the compile result of each compiler here: https://godbolt.org/z/z6TEWxn49
The latest GCC and MSVC compiles this code but clang doesn't.
I cannot find why clang fails, so I'd like to make an issue report, if it's clang's bug.
Is clang right by standard? Or, is it a bug of clang?
Related
According to P1814R0, the template deduction should work for alias with default value. With GCC 12.2(-std=c++20), the following code built successfully. However, in MSVC v19.33(/std:c++20) (which supports P1814R0), I got an error
<source>(10): error C2641: cannot deduce template arguments for 'Matrix3'
Is this a MSVC bug or I missed some configurations in MSVC?
Test codes:
template <typename Type, int Row, int Col, int Options = 0>
class Matrix {
Type storage[Row * Col];
};
template <typename Type = double>
using Matrix3 = Matrix<Type, 3, 3>;
int main() {
Matrix3 a;
return 0;
}
https://godbolt.org/z/nbfaxY7vs
The syntax for saying: I don't want to provide template arguments, just use the defaults, should be:
Matrix3<> a;
Indeed C++20 adopted P1814 into section over.match.class.deduct, so it seems that the following should be valid since C++20:
Matrix3 a;
GCC
As the OP mentions in a comment GCC rejected the above in C++17 and accepts it in C++20.
MSVC
As mention by #康桓瑋 MSVC accepts since C++20 only the form:
Matrix3 a{};
but still rejects:
Matrix3 a;
Clang
Clang still rejects both.
To Summarize
It seems that GCC is updated for C++20 on that respect, MSVC did part of the way and Clang is lagging behind.
I would expect the following code to produce a compiler error because the nested constraint within the requires clause is not a constant expression. However, Clang 15.0.0 seems to be okay with it and compiles it without any errors. This seems to be a regression compared to Clang version 14.0.0, which does produce the expected error. Is there a good reason for this change in behavior or is this simply a compiler bug of Clang?
struct s
{ static auto b() -> bool; };
template<typename T>
concept c = requires
{ requires T::b(); };
static_assert(not c<s>); // fails with Clang 14, GCC 12.2, and MSVC 19.32
I stumbled on a strange interaction between typedef and variadic template parameters that I'd like to understand. The following code compiles with clang but gives an error with GCC:
template<typename T> // no error if this is not a template
struct Traits;
#pragma GCC diagnostic ignored "-Wunused-parameter"
template<typename ...args>
void function(args... e) {}
template<typename T>
struct Caller {
typedef typename Traits<T>::types traits_types; // no error if this is changed to a 'using' directive
template<typename ...types> // no error if the pack is converted to a single parameter
static void method(types... e) {
function<traits_types>(e...);
}
};
GCC behavior
When I compile (not link) this with GCC, I get an error on line 14:
$ g++-9.2.0 -Wall -Wpedantic -Wextra -std=c++11 -c test.cpp
test.cpp: In static member function ‘static void Caller<T>::method(types ...)’:
test.cpp:14:31: error: parameter packs not expanded with ‘...’:
14 | function<traits_types>(e...);
| ~~~~~~~~~~~~~~~~~~~~~~^~~~~~
test.cpp:14:31: note: ‘types’
$
It acts as if GCC first substitutes in the definition of traits_types, which would produce
template<typename ...types>
static void method(types... e) {
function<typename Traits<T>::types>(e...);
}
and then evaluates template parameter substitution, at which point it sees the last occurrence of the token types as an unexpanded parameter pack and produces an error accordingly.
I've tested this with GCC 6.4.0, 7.3.0, 8.2.0, 8.3.0, 9.1.0, and 9.2.0, as well as a couple older versions, and the behavior is consistent among all of them.
clang behavior
However, when I compile this with clang, it works fine.
$ clang++-8 -Wall -Wpedantic -Wextra -std=c++11 -c test.cpp
$
This seems as if it first substitutes in for the parameter pack types and then handles the name traits_types.
I see this behavior consistently in clang 6.0.0, 7.0.1, and 8.0.1, and a couple older versions.
Question
In standard C++11, is GCC correct to give the error that it does, or is the code valid? Or is it undefined/implementation-defined/otherwise unspecified?
I've looked through much of cppreference.com's content on templates and typedefs without finding anything that clearly addresses this case. I also checked several other questions (1, 2, 3, 4, 5, etc.), all of which seem similar but don't quite apply to this situation, as far as I can tell.
If this is in fact a compiler bug, a link to a relevant issue in the bug tracker confirming that GCC (or clang, if applicable) doesn't handle this correctly would settle the question pretty well.
Yes it's a bug. What you observed as "it acts as if GCC first substitutes in the definition of traits_types", is followed by a manifestation of GCC bug 90189:
Source:
struct A {
using CommonName = char;
};
template <typename T, typename... CommonName>
struct B {
using V = typename T::CommonName;
};
template struct B<A>;
Output:
<source>:7:37: error: parameter packs not expanded with '...':
7 | using V = typename T::CommonName;
| ^
<source>:7:37: note: 'CommonName'
Compiler returned: 1
Rejected by all GCC versions. Accepted by clang, msvc.
GCC acts like you wrote typename Traits<T>::types directly, and then it gets confused by the dependent name types being the same as the name of the template parameter pack. You can get around it by giving the pack a different name, but in standard C++ the dependent name can be the same as the name of the pack. Because one must be qualified, whereas the other is unqualified, there should be no ambiguity.
Another "who's right, between g++ and clang++?" question for standard gurus.
Given the following trivial code
#include <utility>
template <std::size_t N, typename = std::make_index_sequence<N>>
struct foo;
template <std::size_t...Is>
struct foo<sizeof...(Is), std::index_sequence<Is...>>
{ };
int main ()
{
foo<3u> f;
(void)f; // just to avoid the "unused variable" warning
}
I have that clang++ compile without problems (clang++ 9.0.0, by example, but also older versions) where g++ (g++ 9.2.0, by example, but also older versions) give me the following compilation error
prog.cc:8:8: error: template argument 'sizeof... (Is)' involves template parameter(s)
8 | struct foo<sizeof...(Is), std::index_sequence<Is...>>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The question, as usual is: who's right?
Or, in other words: is correct my code example?
-- EDIT --
About the other question, I suppose is related, but I don't think this one it's an exact duplicate.
In fact clang++ doesn't compile the code in that question, compile this code.
Otherwise the g++ error is the same and, if I understand correctly, the accepted answer of that question could be an answer also for this question.
Following that answer, if I understand correctly, the code is wrong before cwg 1315, because "A partially specialized non-type argument expression" (sizeof...(Is)) involve "a template parameter of the partial specialization" that isn't "a simple identifier".
After cwg 1315 -- again, if I understand correctly -- the code should be correct because "Each template-parameter" appear once "outside a non-deduced context".
I believe that I have found a problem with gcc's alias template handling. Essentially, gcc appears to fail to correctly substitute the alias's template-id for an alias template instantiation when referring to the types by reference.
I was able to whittle a messy real-world problem down to a minor variation on the non-normative example provided in the C++ 11 standard section temp.alias (14.5.7/2):
#include <vector>
using namespace std;
template <class T>
using Vec = vector<T, allocator<T>>;
template <template <class> class TT>
void f1(TT<int> v);
template <template <class> class TT>
void f2(TT<int>& v);
template <template <class, class> class TT>
void g1(TT<int, allocator<int>> v);
template <template <class, class> class TT>
void g2(TT<int, allocator<int>>& v);
void foo()
{
Vec<int> v;
f1(v); // gcc and clang both correctly yield no matching function error
g1(v);
f2(v); // clang yields a no matching function error
g2(v); // gcc yields a no matching function error
}
As noted above, clang 3.3 (recent pull from svn) and gcc (4.7.2, 4.8.0, and 4.8.1) agree on the handling of f1/g1 in conformance with the standard, but differ on the handling of f2/g2 (to be clear, all tested versions of gcc accept the call to f2() and error on the call to g2()). The difference between f1/g1 and f2/g2 is of course that the latter pair uses a reference parameter.
All indications, both in this example and in my real problem, are that gcc is not correctly converting the type of the instantiation of the alias template (e.g. Vec<int>) to the aliased type (e.g. vector<int, allocator<int>>) prior to trying to deduce the template parameter for the instantiations of f2 and g2.
My question is: first, is indeed gcc incorrect and clang correct here, and second, is there any straightforward way (other than not using the alias template) to convince gcc to reject f2 and match g2.
Indeed this is a GCC bug. One workaround is to simply add a typedef.
typedef Vec<int> vit;
vit v;
Given that this is effective, an identity metafunction would probably also work.
It looks like the compiler has issue with the inference. Explicitly invoking the template enables a work around -- I can't speak to why gcc fails to infer as well as icpc or clang.
For icpc (ICC) 13.1.0 20130121:
f1<Vec> (v); // gcc and clang both correctly yield no matching function error
g1(v);
f2<Vec>(v); // clang yields a no matching function error
g2(v); // gcc yields a no matching function error
For gcc (GCC) 4.7.2 20121109 (Red Hat 4.7.2-8):
f1<Vec> (v); // gcc and clang both correctly yield no matching function error
g1(v);
f2<Vec>(v); // clang yields a no matching function error
g2<vector>(v); // gcc yields a no matching function error