The discussion first takes place at llvm/llvm-project#60377. After reading temp.constr.atomic and temp.constr.normal again and again, I feel even more confused about this question beacause of my poor English.
Like the example below, in order to help clang-format format requires clause correctly, I used to add a pair of bracket. Now I changed my style. When I tried to change my code, the unexpected error happened.
#include <concepts>
template <typename T>
requires std::integral<T>
struct [[nodiscard]] Widget;
template <typename T>
requires(std::integral<T>) // error: Requires clause differs
struct [[nodiscard]] Widget {
T value;
};
[[nodiscard]] auto main() -> int {
Widget<int> widget{1};
return widget.value;
}
I tested this with different compilers. It turns out:
error - x86_64 clang (trunk)
pass - x86_64 gcc (trunk)
error - x64 msvc v19.latest
What is the expected behaviour according to the standard, clang/msvc or gcc?
What is the expected behaviour according to the standard, clang/msvc or gcc?
The standard does not require any particular behaviour (C++23 CD [intro.compliance.general] paragraph 2). The program is ill-formed, no diagnostic required because the validity of the program depends on whether or not the template-heads are equivalent ([basic.link] paragraph 11) and they are functionally equivalent but not equivalent ([temp.over.link] paragraph 7).
Related
The following compiles without error in VS2019 (version 16.11.15) with C++ 17 selected as the language. But it fails with C++ 20 with error "error C2027: use of undefined type 'Anon'"
template <typename T> class a_template
{
public:
void do_something(class Anon& anon) const;
};
template <typename T> void a_template<T>::do_something(class Anon& anon) const
{
anon.do_something();
}
The Anon class is of course undefined but the ::do_something function is unused so does not need to be instantiated. This is OK in C++17 but apparently not in C++20.
Is this a change in language rules? If so, can it be fixed without actually defining Anon?
Is this a change in language rules?
No, this is due to the fact that a C++ compiler is permitted (but not required!) to diagnose errors at the time the template is parsed
when all of the instantiations of the template would produce that error.
This means that for your given example, at the time of parsing the definition compilers may or may not issue an error. That is, the compiler can produce an error when parsing the template or may wait until the first template instantiation. Refer to demo where msvc doesn't issue an error but gcc and clang does.
Perhaps a simpler example would make it more clear :
void func()
{
}
template<typename T> void bar()
{
func(3); //compilers are allowed(but not required) to issue error at the time of pasrsing this
}
In the above example, func is a nondependent name and at the point where we have called func using func(3), the only visible func is the one that accepts 0 arguments and not one. And as i said earlier, some compiler may issue an error(at the time of parsing) even though we've not instantiated bar but some compilers may not. This is because they are allowed to but not required to do so. See demo where msvc doesn't issue an error here but gcc and clang does.
The same logic applies to your example as well. Meaning as Anon is an incomplete type and you have anon.do_something(), some compiler might choose to produce an error even though you have not instantiated a_template and some other compiler might not.
I ran across a problem upgrading templated array references to std::array where I had used this:
template<class T, int N>
void f(T(&a)[N]){/* do stuff */;}
This has worked in all compilers I have used so I just did this when changing to std::array
template<class T, int N>
void f(std::array<T,N>& a){/* do stuff */;}
And this worked fine on MSVC. But when I ran the code on other compilers it did not
The following code works in MSVC but not other compilers. See https://godbolt.org/z/d9cqWMeaM which fails to match because N must be std::size_t.
*This question indicates that SFINAE should apply. However, as noted in the comments and in spite of the that answer, SFINAE, typically applies to rejection of malformed declarations. This is a deduction failure.
Is MSVC's acceptance of this code a compiler bug? And is the T(&a)[N] where int N was used legal even though all compilers I've ever used had no problem at all?
This was somewhat annoying because some of the prior code used the fact N was signed in various places.
std::array size_type is specified as std::size_t.
GCC and Clang are right, template deduction should fail in this case, according to [temp.deduct.type]/18:
If P has a form that contains <i>, and if the type of i differs from the type of the corresponding template parameter of the template named by the enclosing simple-template-id, deduction fails.
. . .
[ Example:
template<int i> class A { /* ... */ };
template<short s> void f(A<s>);
void k1() {
A<1> a;
f(a); // error: deduction fails for conversion from int to short
f<1>(a); // OK
}
Note: in C++11 this rule was a little more human-readable, see here.
So technically MSVC's acceptance of the code is a bug. I would report it to the vendor (Help -> Send Feedback -> Report a Problem).
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".
Both GCC (5.3.0) and Clang (3.8.0) agree that this is valid code:
constexpr std::integral_constant<size_t, 0> n{};
std::get<n>(std::make_tuple(123));
However, they disagree on this:
std::integral_constant<size_t, 0> n;
std::get<n>(std::make_tuple(123));
Clang is ok with it, but GCC reports "the value of 'n' is not usable in a constant expression" / "'n' was not declared 'constexpr'".
Whose behaviour matches the standard?
Clang is right, although it ultimately depends on your library implementation. The standard does not per se disallow calling a constexpr function for a non-const(expr) object in constant expressions; only usage of that object's members would be a problem (see [expr.const]/(2.7.3)). Since the conversion operator most certainly simply returns 0, it's probably a GCC bug (also suggestive when considering the error message).
This is more of a c++ standards question.
Consider the following code:
template <typename T>
class has_Data
{
typedef char one;
typedef long two;
template <typename C> static one test( typeof(&C::Data) ) ;
template <typename C> static two test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
class MyClass {
private:
struct Data {
};
};
void function(bool val = has_Data<MyClass>::value) {}
The above code works with gcc (GCC) 4.4.3
However with clang version 3.3 (2545b1d99942080bac4a74cda92c620123d0d6e9) (2ff97832e593926ea8dbdd5fc5bcf367475638a9)
it gives this error:
test_private_data.cpp:7:54: error: 'Data' is a private member of 'MyClass'
template <typename C> static one test( typeof(&C::Data) ) ;
^
/devshared/home/rhanda/test_private_data.cpp:7:37: note: while substituting explicitly-specified template arguments into function template 'test'
template <typename C> static one test( typeof(&C::Data) ) ;
^
/devshared/home/rhanda/test_private_data.cpp:21:26: note: in instantiation of template class 'has_Data<MyClass>' requested here
void function(bool val = has_Data<MyClass>::value) {}
^
1 error generated.
Which one is right?
From standard document (n3485), I found a statement which seems to agree with clang more than gcc.
Access control is applied uniformly to all names, whether the names are referred to from declarations or expressions.
I would assume that GCC is right.
The first thing to note is that no non-friend code should be able to positively report the existence of a given private member. So if that is what you try to do, you have to modify your design. A class can do anything with its private members, and other code (excepting friends) should have no way to know about it. That's by design.
However, there is the SFINAE principle: substitution failure is not an error. Since MyClass::Data is private, the code in has_Data should – in my opinion – act as if there was no C::Data member at all. Hence the first function would lead to a substitution failure, which gets silently ignored, and the second function is the one used. Adding a bit more code, my GCC 4.7.2 compiles this without issues and with has_Data<MyClass>::value evaluating to false. Correct SFINAE in my opinion.
Trying to back this opinion up with a quotation from the document you referred to, I found the following in section 14.8.2 paragraph 8:
Note: Access checking is done as part of the substitution process.
This is a non-normative note in the standard, but to me appears to be a very readable and clear indication that SFINAE should in fact apply in this situation, just the way GCC handles it.
Edit: As #hvd pointed out in a comment, the above is only true for C++11. In older versions of the standard, the situation used to be different. Issue 1170: Access checking during template argument deduction has details on that change.
GCC will not compile this code with -std=c++03 or -std=c++11 due to the fact that typeof is a GNU extension. The fact that -std=gnu++03 still compiles the code might perhaps be considered inappropriate, but since the way forward is using the C++11 semantics, I wouldn't bother filing a report about this.