Resolving compilation errors for c++20 code on Mac - c++

I am trying to setup my machine to be able to compile c++20 code. I have a simple example code
#include <concepts>
#include <iostream>
template<typename T>
requires std::integral<T>
auto gcd(T a, T b) {
if(b == 0) return a;
else return gcd(b, a%b);
}
int main() {
std::cout << "\n";
std::cout << gcd(100,10) << "\n";
}
which I am trying to compile on a MacOS (11.5.1/BigSur).
xcode version - Xcode 12.5.1
Build version 12E507
clang version - Apple clang version 12.0.5 (clang-1205.0.22.11)
compilation command
g++ -std=c++20 myfile.cpp
I get the following error:
myfile.cpp:25:24: error: 'T' does not refer to a value
requires std::integral<T>
^
myfile.cpp:24:19: note: declared here
template<typename T>
^
myfile.cpp:25:15: error: no member named 'integral' in namespace 'std'; did you mean 'internal'?
requires std::integral<T>
~~~~~^~~~~~~~
internal
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/ios:960:1: note: 'internal' declared here
internal(ios_base& __str)
^
myfile.cpp:26:1: error: expected expression
auto gcd(T a, T b) {
^
3 errors generated
Need help with this.

Related

C++20 concepts support in CLang

I'm trying to compile an example of some concept from cppreference with Clang on Mac and it fails. How can I fix the issue and compile the example?
Code:
#include <concepts>
#include <iostream>
template<std::regular T>
struct Single {
T value;
friend bool operator==(const Single&, const Single&) = default;
};
int main()
{
Single<int> myInt1{4};
Single<int> myInt2;
myInt2 = myInt1;
if (myInt1 == myInt2)
std::cout << "Equal\n";
std::cout << myInt1.value << ' ' << myInt2.value << '\n';
}
Terminal output:
% g++ -std=c++20 -o a a.cpp
a.cpp:4:15: error: no type named 'regular' in namespace 'std'
template<std::regular T>
~~~~~^
a.cpp:6:5: error: unknown type name 'T'
T value;
^
a.cpp:12:12: error: template argument for non-type template parameter must be an expression
Single<int> myInt1{4};
^~~
a.cpp:4:23: note: template parameter is declared here
template<std::regular T>
^
a.cpp:13:12: error: template argument for non-type template parameter must be an expression
Single<int> myInt2;
^~~
a.cpp:4:23: note: template parameter is declared here
template<std::regular T>
^
4 errors generated.
Compiler version:
% g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 12.0.5 (clang-1205.0.22.11)
Target: x86_64-apple-darwin20.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
What's interesting is that the example successfully compiles on GodBolt with lower CLang version (12.0.1)

Template c++ compiler differences VC++ different output

I had written some c++ code in Visual Studio and was trying to run it on my c++ code on a linux server. When I tried to compile it with G++ however, it failed to compile with tons of errors. I looked through the error and was able to simplify the problem to this:
template<int x>
struct Struct
{
template<int y>
static void F()
{
//Struct<x>::F<0>(); // compiles
//Struct<y>::G(); // compiles
Struct<y>::F<0>(); // does not compile?
}
static void G()
{
}
};
int main ()
{
Struct<0>::F<0>();
}
On Visual Studio this code compiles just fine but on G++ or Clang++, it fails to compile. Errors on G++ 8.3.0:
test.cpp: In static member function ‘static void Struct<x>::F()’:
test.cpp:9:19: error: expected primary-expression before ‘)’ token
Struct<y>::F<0>(); // does not compile?
^
test.cpp: In instantiation of ‘static void Struct<x>::F() [with int y = 0; int x = 0]’:
test.cpp:19:18: required from here
test.cpp:9:15: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘int’ to binary ‘operator<’
Struct<y>::F<0>(); // does not compile?
Errors on Clang++:
5691311/source.cpp:9:19: error: expected expression
Struct<y>::F<0>(); // does not compile?
^
See it live: https://rextester.com/AAL19278
You can change the compiler and copy the code to see the different errors.
Is there anyway I could get around this problem so that my code will compile on G++ or Clang++?
Original Code:
template<int x, int y>
ThisType add()
{
return ThisType::Create(this->x() + x, this->y() + y);
}
ResultPos to = p.add<0, 1>();
template<int x>
struct Struct
{
template<int y>
static void F()
{
Struct<y>::F<0>(); // does not compile?
}
};
should not compile. You need to specify for the compiler that F in fact requires a template list, since F is a dependent template type. Otherwise the compiler will assume that the next < is a smaller than.
template<int x>
struct Struct
{
template<int y>
static void F()
{
Struct<y>::template F<0>();
}
};
I assume Struct<x>::F<0> works, since the compiler already knows that the current type is Struct<x>, but it cannot know that y is the same as xin this case.

Deleted template function works on gcc, but not on clang [duplicate]

This question already has an answer here:
Specialized template function with deleted "general" case fails to compile with g++ <=4.8.0 and clang++
(1 answer)
Closed 5 years ago.
I am having trouble with a template specialisation of a deleted template function. The code below shows the problem boiled down to a MWE:
#include <iostream>
#include <string>
template<typename T>
inline std::string typeToString() = delete;
template<>
inline std::string typeToString<float>()
{
return "float";
}
int main()
{
std::cout << typeToString<float>() << std::endl;
}
With gcc 7 this compiles fine. However, with Apple LLVM 8.0.0 I get the following error messages:
clang test.cpp -std=c++1z
test.cpp:8:28: error: inline declaration of 'typeToString<float>' follows non-inline definition
inline std::string typeToString<float>()
^
test.cpp:8:28: note: previous definition is here
test.cpp:15:18: error: call to deleted function 'typeToString'
std::cout << typeToString<float>() << std::endl;
^~~~~~~~~~~~~~~~~~~
test.cpp:8:28: note: candidate function [with T = float] has been explicitly deleted
inline std::string typeToString<float>()
This looks to be a bug. If you compile with clang 3.9.1 or above it will compile. The following examples on Golbolt and Wandbox with clang 3.8.1 fail but when we change to 3.9.1 they both compile.

use type_traits to limit type of template member function

I'm writing a template class with a method that performs some bitwise operations, so I want to limit the type in the case this method is used within is_integral. I took the simple example here and modified a bit as follows:
#include <iostream>
#include <type_traits>
template <typename T>
class A
{
public:
A();
T foo(T i) {
static_assert(std::is_integral<T>::value, "Integer required.");
return (i & 2);
}
private:
T x;
};
int main() {
A<double> a;
std::cout << a.foo(3) << std::endl;
return 0;
}
However, compiler gives me 2 compile errors at static_assert():
static_assert failed "Integer required."
and at return (i & 2);:
invalid operands to binary expression ('double' and 'double')
My question is, if it will show the error at line return (i & 2); anyway, using type_traits to check for type here seems useless? And, is there anyway to throw the error to console output when it runs, instead of making it unable to be compiled?
My question is, if it will show the error at line return (i & 2); anyway, using type_traits to check for type here seems useless?
It's true that it's unfortunate that you get subsequent compile errors anyway, but which compile error do you find more readable?
"Integer required."
invalid operands to binary expression (double and double)
I know what I did wrong about the first one - I have A<double> but foo() requires an integer. No idea about the second. Am I misusing your class template or does it have a bug?
And, is there anyway to throw the error to console output when it runs, instead of making it unable to be compiled?
You want it to be a compile error. Catching errors at compile time is a lot better than catching errors at compile time.
Compiler is trying to report as many errors as it can. static_assert reports an error, but there is another error as well (using double argument for &) so it also is reported.
If you want to limit output to one error, you should have two sfinae-enabled overloads and have a second one (for anything but integrals) consist of a single static_assert.
As for your last question, the whole purpose of doing static_assert is to trigger errors at compile time, not runtime.
Here's another way to achieve the same thing. You may or may not prefer the error messages:
#include <iostream>
#include <type_traits>
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
class A
{
public:
A();
T foo(T i) {
return (i & 2);
}
private:
T x;
};
int main() {
A<double> a;
std::cout << a.foo(3) << std::endl;
return 0;
}
sample errors:
In file included from /opt/gcc-5.3.0/include/c++/5.3.0/bits/move.h:57:0,
from /opt/gcc-5.3.0/include/c++/5.3.0/bits/stl_pair.h:59,
from /opt/gcc-5.3.0/include/c++/5.3.0/bits/stl_algobase.h:64,
from /opt/gcc-5.3.0/include/c++/5.3.0/bits/char_traits.h:39,
from /opt/gcc-5.3.0/include/c++/5.3.0/ios:40,
from /opt/gcc-5.3.0/include/c++/5.3.0/ostream:38,
from /opt/gcc-5.3.0/include/c++/5.3.0/iostream:39,
from /tmp/gcc-explorer-compiler11636-75-1ve7gbt/example.cpp:1:
/opt/gcc-5.3.0/include/c++/5.3.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = std::integral_constant<bool, false>::value; _Tp = void]':
19 : required from here
/opt/gcc-5.3.0/include/c++/5.3.0/type_traits:2388:61: error: no type named 'type' in 'struct std::enable_if<false, void>'
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
^
/tmp/gcc-explorer-compiler11636-75-1ve7gbt/example.cpp: In function 'int main()':
19 : error: template argument 2 is invalid
A<double> a;
^
20 : error: request for member 'foo' in 'a', which is of non-class type 'int'
std::cout << a.foo(3) << std::endl;
^
Compilation failed

Workaround for GCC 4.9 constexpr bug

I have the following piece of code which represents an actual bigger piece of code:
#include <iostream>
using namespace std;
template<size_t N> class A {
public:
static constexpr size_t getN() {return N;}
};
template<size_t N> class B {
public:
void print() { cout << "B created: " << N << '\n';}
};
template <class T> class C {
public:
void set(T* a) {
t_ptr = a;
}
void create() {
constexpr int m = t_ptr->getN();
B<m> b;
b.print();
}
private:
T* t_ptr;
};
int main() {
constexpr int n = 2;
A<n> a;
C<A<n> > c;
c.set(&a);
c.create();
}
Compiling with g++ -o main main.cpp -std=c++11 and GCC/G++ 4.8.3 the expected output is received:
B created: 2
However, with GCC/G++ 4.9.1 the code does not compile, output:
main.cpp: In member function ‘void C<T>::create()’:
main.cpp:27:15: error: the value of ‘m’ is not usable in a constant expression
B<m> b;
^
main.cpp:26:27: note: ‘m’ used in its own initializer
constexpr int m = t_ptr->getN();
^
main.cpp:27:16: error: the value of ‘m’ is not usable in a constant expression
B<m> b;
^
main.cpp:26:27: note: ‘m’ used in its own initializer
constexpr int m = t_ptr->getN();
^
main.cpp:27:19: error: invalid type in declaration before ‘;’ token
B<m> b;
^
main.cpp:28:15: error: request for member ‘print’ in ‘b’, which is of non-class type ‘int’
b.print();
^
This is caused by a known bug in GCC 4.9: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59937 and in this older thread https://gcc.gnu.org/ml/gcc-bugs/2013-11/msg00067.html the usage of extern is proposed as a workaround. However, I am not able to get this workaround working.
Could you guys help me to make this code compile in GCC 4.9? Thank you!
Since this is not constexpr the access to this->t_ptr is not either.
clang's error is a bit more helpful
implicit use of 'this' pointer is only allowed within the
evaluation of a call to a 'constexpr' member function
Referring to:
N3690 5.19/2 (emphasis added)
A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:
— this, except in a constexpr function or a constexpr constructor that is being evaluated as
part of e;
Calling the static member function via the typename works
constexpr int m = T::getN();