Different behavior of consteval in GCC and MSVC (not work) - c++

Consider the following code:
#include <cstdint>
#include <vector>
class ClassT
{
public:
consteval static size_t GetSize()
{
return sizeof(int);
}
void Resize()
{
_Data.resize(GetSize(), 0);
}
std::vector<uint8_t> _Data;
};
int main()
{
ClassT Object;
Object.Resize();
return 0;
}
GCC compiles it successfully, but MSVC gives the following error:
error C7595: 'ClassT::GetSize': call to immediate function is not a constant expression
Am I missing something? Or is it really an MSVC bug?
Compilers version: x86-64 gcc 10.2 and x64 msvc v19.28. (Link to godbolt)

This looks like an MSVC bug. It might even be the same as this existing one- #1224555.
Minimal example:
consteval int test() { return 0; }
int main() {
return test(); // error C7595: 'test': call to immediate function is not a constant expression
}

Related

Weird error from Visual C++: No default constructor for promise type

Suppose I want to use coroutines with C++20 and restrict the promise type to accept only functions getting one argument of type int &. I write the following code:
#include <coroutine>
struct task {
struct promise_type {
promise_type(int &) {}
task get_return_object() { return {}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
};
task my_task(int &) {
co_await std::suspend_never{};
}
int main() {
int x = 5;
my_task(x);
}
This compiles and works fine, both with GCC version 10+ and Visual Studio 2019 version 16.8+.
However, Visual Studio 2019 always complains that no default constructor exists for class "task::promise_type":
This error does not occur if I do not use a reference (e.g. int instead of int & as the argument type).
GCC does not show any warning or error, with and without the reference.
Am I doing something wrong?
Is this prohibited by the standard?
Or is it just a weird quirk of IntelliSense?
This seems to be a problem of IntelliSense and should work fine. To resolve the intellisense error, a constructor can be added just for IntelliSense:
#ifdef __INTELLISENSE__
promise_type();
#endif

Clang report "constexpr if condition is not a constant expression" while GCC is ok [duplicate]

This question already has answers here:
Static member access in constant expressions
(2 answers)
Closed 2 years ago.
I'm using clang 9.0.1 and gcc 9.2.1 on x64 Linux, both with --std=c++17 (or --std=c++2a).
Gcc can build the following example without any error or warning, while clang++ reports error: constexpr if condition is not a constant expression on both if constexpr lines. (btw, on my MacBook, Apple clang-11.0.0 reports the same error too.)
MCVE:
#include <utility>
enum class TopicType {
MarketData = 'M',
Timer = 'T',
};
template<class Topic>
struct TopicBase {
constexpr static TopicType type() { return Topic::type; };
const Topic& topicImp;
explicit TopicBase(const Topic &t) : topicImp(t) {}
};
struct MarketDataTopic {
static constexpr TopicType type{TopicType::MarketData};
};
struct TimerTopic {
static constexpr TopicType type{TopicType::Timer};
};
template<class Topic>
int subscribe(TopicBase<Topic>&& topic) {
if constexpr (topic.type() == TopicType::MarketData) { // <-- clang++ reports error here
return 1;
}
if constexpr (topic.type() == TopicType::Timer) { // and error here
return 2;
}
return -1;
}
int main(int argc, const char **argv) {
MarketDataTopic m{};
TimerTopic t{};
TopicBase<MarketDataTopic> b1{m};
TopicBase<TimerTopic> b2{t};
subscribe(std::move(b1));
return 0;
}
Online compiler https://godbolt.org/z/rARi_N has the same result.
So which compiler is right about this? And if it is an error, how to fix it for clang?
Well you can do this to make it work for clang:
template<class Topic>
int subscribe(TopicBase<Topic>&& topic) {
using myType = TopicBase<Topic>;
if constexpr (myType::type() == TopicType::MarketData) { // <-- clang++ reports error here
return 1;
}
if constexpr (myType::type() == TopicType::Timer) { // and error here
return 2;
}
return -1;
}
Run live
Most probably that's a bug in clang. Better report it.

Lambdas, Is this keyword needed to disambiguate const/non-const member functions?

When I use MSVC to compile this program, I receive the error,
"Example::bar ambiguous call to overloaded function"
Then, I found that the this keyword was able to resolve the error. Surprised, I used rextester and found that both Clang and GCC were able to compile the program without the this keyword.
Here is the program in question.
#include <iostream>
class Example {
public:
Example() {
auto lambda = [this]() {
//this->bar<int>(); // Using this allows the program to compile and run successfully.
bar<int>(); // This doesn't work in MSVC
};
lambda();
}
template<typename T>
void bar() {
std::cout << "(non-const) bar\n";
}
template<typename t>
void bar() const {
std::cout << "(const) bar\n";
}
};
int main() {
Example example;
}
Ultimately I am asking, is this keyword needed in a lambda to disambiguate between const and non-const member functions and whether MSVC is correct or GCC and Clang are correct.
I am using Visual Studio 2017 and the full version of MSVC is 191627027

C++ - Errors when trying to insert class into map

I have a map like so map<string, unique_ptr<Base>> variables and I am trying to insert data into the map variables.insert(make_pair("foo", new Int(10))) but I am getting to following errors:
error: no matching function for call to ‘std::map<std::__cxx11::basic_string<char>, std::unique_ptr<Base>>::insert(std::pair<const char*, Int*>)’
variables.insert(make_pair("test", new Int(10)));
error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
template<typename _Pair, typename = typename
This is my code:
class Base {
public:
Base() {};
virtual ~Base() {};
};
class Int : public Base {
public:
Int(int i) {
this->i = i;
}
Int operator=(int i) {
this->i = i;
}
int i;
};
void set() {
map<string, unique_ptr<Base>> variables;
variables.insert(make_pair("test", new Int(10)));
}
I think I need a fresh pair of eyes to look at this I'm not sure what this issue is, thanks!
Edit
I'm trying to make a heterogeneous map and there's a class for each data type. But I still get the same error no matter how many there are.
Note: This answer only applies to older versions of the main three compilers:
GCC: Applies to 5.3.1 or earlier. May apply to any version earlier than 6.1.0, but I haven't tested this.
Clang: Applies to 3.7.1 or earlier. May apply to any version earlier than 3.8.0, but I haven't tested this.
Visual Studio: Applies to 19.00.23506.0 or earlier. May apply to any version earlier than 19.00.23720.0, but I haven't tested this.
Conversely, if you have GCC 6.1.0 or later, Clang 3.8.0 or later, or Visual Studio 19.00.23720.0 or later, the original code should compile as is, without either of the modifications suggested in this answer.
[Thanks goes to AndyG for pointing out that it works with later versions of GCC & Clang.]
The problem appears to be that it isn't creating your unique_ptr from your raw pointer.
If you can use C++14, try std::make_unique().
void set() {
map<string, unique_ptr<Base>> variables;
variables.insert(make_pair("test", make_unique<Int>(10)));
}
If you can't, then try something like this:
void set() {
map<string, unique_ptr<Base>> variables;
variables.insert(make_pair("test", unique_ptr<Int>(new Int(10))));
}
Interestingly, I noticed a slight difference in how different compilers handle this. Using the following slightly modified version of your code as a test program:
#include <map>
#include <memory>
#include <iostream>
class Base {
public:
Base() {};
virtual ~Base() {};
};
class Int : public Base {
public:
Int(int i) {
this->i = i;
}
Int& operator=(int i) {
this->i = i;
// You forgot to return something.
return *this;
}
int i;
};
void set() {
using namespace std;
map<string, unique_ptr<Base>> variables;
variables.insert(make_pair("test", new Int(10)));
// C++14:
// variables.insert(make_pair("test", make_unique<Int>(10)));
// C++11:
// variables.insert(make_pair("test", unique_ptr<Int>(new Int(10))));
// Cheap hack for testing.
cout << static_cast<Int*>(variables["test"].get())->i << endl;
}
int main() {
set();
}
Most compilers* will fail to compile this, unless the initial line is commented out and either of the fixes is uncommented. However, the online MSVC compiler seemed to be able to compile it fine, without needing to uncomment either of the lines. Curiously, the version of MSVC available on Rextester failed to compile it without uncommenting one of the two lines.
* Tested online, with TutorialsPoint GCC, MSVC 2015 online, and Rextester Clang, GCC, and MSVC.

Clang++ Xcode 4.4 Non Static Member Initialization and Move constructor

I am using Xcode 4.4 with mountain lion. I can't seems to understand why non-static member initalization in templates invokes a move constructor for the variable. Is there anyway to overcome this error?
Example Code:
#include <iostream>
#include <atomic>
//
// This class can compile
//
class Working
{
public:
int GetValue() { return value_; }
private:
std::atomic<int> value_{0};
};
//
// This class cannot compile
//
template <typename Ty1>
class NotWorking
{
public:
int GetValue() { return value_; }
private:
std::atomic<int> value_{0}; // <---- error here
};
int main(int argc, const char * argv[])
{
Working working;
NotWorking<int> not_working;
return 0;
}
Xcode 4.4 and Clang throws the error in that line saying:
"Copying member subobject of type 'std::atomic<int>' invokes deleted constructor"
This looks like a clang bug on the open source svn trunk repository. Could you submit a bug report against clang here: http://llvm.org/bugs/ ?
Thanks!