I have a piece of C++ code used std::tuple. I have enabled C++17 standard in both MSVC and g++. But it can only be built by g++.
As follows:
#include <future>
#include <utility>
#include <typeindex>
int main()
{
std::packaged_task<std::tuple<std::type_index, int>()> task{
[]() {return std::make_tuple(std::type_index(typeid(int)), 3); }
};
}
Error in MSVC:
Severity Code Description Project File Line Suppression State
Error C2512 'std::tuple::tuple': no appropriate default constructor available TestConsole C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.23.28105\include\future 213
I've also tried this, seems like it can't accept a type that don't have any default constructor:
#include <future>
#include <utility>
class Foo
{
public:
Foo() = delete;
Foo(int a) { a_ = a; }
int a_;
};
int main()
{
std::packaged_task<std::tuple<Foo, int>()> task{
[]() {return std::make_tuple(Foo(3), 3); }
};
}
I'm wondering what caused the problem and how can I solve it(or is there a better way?).
Any help will be really appreciated.
Edit: I've change int* into int. I don't think nullptr or int* is the point. It also can't be built. Thanks a lot.
Edit: I'm currently using Visual Studio 2019 (version 16.3.8)
Related
Let's consider the following code:
output_data.hpp
#pragma once
#include <functional>
#include <cstddef>
namespace example {
using Callback = std::function<void(int)>;
struct OutputData {
void * data = nullptr;
std::size_t size = 5;
Callback callback = nullptr;
};
} // namespace example
buffer.hpp
#pragma once
#include <vector>
namespace example {
template <typename T>
struct Buffer {
Buffer(std::size_t size);
std::vector<T> buffer_;
};
} // namespace example
buffer.cpp
#include "buffer.hpp"
#include "output_data.hpp"
namespace example {
template <typename T>
Buffer<T>::Buffer(std::size_t size) : buffer_(size)
{
}
template struct Buffer<OutputData>;
} // namespace example
main.cpp
#include <iostream>
#include <memory>
#include <functional>
#include "buffer.hpp"
namespace example {
using Callback = std::function<void(int)>;
struct OutputData {
Callback callback = nullptr;
};
}
int main() {
std::shared_ptr<int> ptr = std::make_shared<int>(5);
example::Buffer<example::OutputData> buf(3);
example::Callback simple_callback = [=](int a) {
std::cout << a << *ptr << "\n";
};
buf.buffer_[1].callback = simple_callback;
}
[Godbolt][https://godbolt.org/z/EEzE7oerb]
The compilation ends without errors, while the execution ends with Segmentation Fault. Segfault is caused by the fact that in main.cpp I used a different struct than the one in buffer.cpp during explicit instantiation. Why was the code compiled without errors?
Is it possible to detect such programming mistakes during compilation? Is there any warning flag for detecting such cases ?
Why was the code compiled without errors?
Credit to Richard Critten's comment for the source.
"The compiler is not required to diagnose this violation, but the behavior of the program that violates it is undefined"
Is it possible to detect such programming mistakes during compilation?
Yes, see below.
Is there any warning flag for detecting such cases ?
Your ODR violation does not exist during compilation of any single source file. It only exists during (after) linking.
g++ will, unless disabled, warn of ODR violations during link time if Link Time Optimization is enabled with the flag -flto
[Godbolt]
I'm getting the following error during compilation:
Severity Code Description Project File Line Suppression State
Error C2664 'mytest::Test::Test(const mytest::Test &)': cannot convert argument 1 from '_Ty' to 'const mytest::Test &' TotalTest C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\include\xutility 158
I have no idea what is, so I'm putting the code here to exemplify what was being done:
TotalTest.cpp
include <iostream>
#include "Test.h"
using namespace mytest;
int main()
{
std::cout << "Hello World!\n";
new Test();
}
Test.h
#pragma once
#include "Test.h"
#include <iostream>
namespace mytest
{
using namespace std;
class Test
{
public:
Test();
~Test();
shared_ptr<Test> t;
};
}
Test.cpp
#include "Test.h"
namespace mytest
{
Test::Test()
{
}
Test::~Test()
{
}
}
TestFactory.h
#pragma once
#include "Test.h"
#include <iostream>
namespace mytest
{
using namespace std;
class TestFactory
{
public:
TestFactory();
shared_ptr<Test> CreateTest(int testClass);
};
}
TestFactory.cpp
#include "TestFactory.h"
namespace mytest
{
TestFactory::TestFactory()
{
}
shared_ptr<Test> TestFactory::CreateTest(int testClass)
{
return make_shared<Test>(new Test());
}
}
I'm using Visual Studio C++ language standard: ISO C++14 Standard (/std:c++14)
In TestFactory::CreateTest(), make_shared<Test>(new Test()) is wrong, as Test does not have a constructor that accepts a Test* pointer as input.
You need to use make_shared<Test>() instead, letting make_shared() call the default Test() constructor for you:
shared_ptr<Test> TestFactory::CreateTest(int testClass)
{
return make_shared<Test>();
}
Any parameters you pass to make_shared() are passed to the constructor of the type specified in the template argument. In this case, there are no parameters needed.
The error comes from the following line:
return make_shared<Test>(new Test());
There are 2 ways of initializing a std::shared_ptr:
Using the std::shared_ptr constructor directly, which requires you to pass a Test object already allocated on the heap, e.g.:
std::shared_ptr<Test> p{ new Test() };
Using make_shared(), which performs the heap allocation internally, e.g.:
std::shared_ptr<Test> p{ std::make_shared<Test>() };
Where in the parentheses you can pass parameters to the constructor of Test.
The 2nd option is usually prefered. You can see more info here: Difference in make_shared and normal shared_ptr in C++
In addition:
Test.h should not include itself (it has #include "Test.h" at the top).
You should avoid using using namespace std;. More info here: Why is "using namespace std;" considered bad practice?
I am learning about smart pointers and when trying to compile the following "stupid" code I get an error.
#include <memory>
#include <iostream>
class Test
{
std::string myString="dumm";
};
int main()
{
std::unique_ptr<Test> test(new Test());
std::cout<<test->myString<<std::endl;
return 0;
}
I just wanted to see, whether this works but I get :"Applying -> to std::unique_ptr instead of a pointer", which seems weird.
I am using c++ 11
Eit: The error is now fixed and I cancompile the above code. However, CLion still gives me "Cant apply -> to std::uniq_ptr"-stuff, which seems to be an error with the IDE
In a class the default visibility is private which makes the myString field invisible to the test object. Make it public:
#include <iostream>
#include <memory>
#include <string>
class Test {
public:
std::string myString = "dumm";
};
int main() {
std::unique_ptr<Test> test(new Test());
std::cout << test->myString;
}
Prefer std::make_unique to direct use of new if compiling for C++14 and later:
std::unique_ptr<Test> test = std::make_unique<Test>();
This function is not available in the C++11 standard which is what you are using.
I try to compile some code which is very similar to:
#include <string>
#include <unordered_map>
class A{
};
int main(int argc, char* argv[]){
std::unordered_map<std::string, std::reference_wrapper<const A>> stringToRef;
A a;
const A& b = a;
stringToRef.insert(std::make_pair("Test", b));
return 0;
}
But can't figure out, why it's not compiling. I'm pretty sure, that the same code compiled fine on MS Visual Studio 2012 - but on Visual Studio 2013, it reports the following compilation error:
error C2280: std::reference_wrapper<const A>::reference_wrapper(_Ty &&): attempting to reference a deleted function
I tried to add copy, move, assignment operators to my class - but couldn't get rid of this error. How can I find out exactly, which deleted function this error refers to?
You want to store a std::reference_wrapper<const A>, so you can use [std::cref][1] to get that directly from a:
#include <functional>
#include <string>
#include <unordered_map>
#include <utility>
class A{
};
int main(int argc, char* argv []){
std::unordered_map<std::string, std::reference_wrapper<const A>> stringToRef;
A a;
stringToRef.insert(std::make_pair("Test", std::cref(a)));
return 0;
}
This works with GCC/Clang+libstdc++, Clang+libc++, and MSVS 2013 (tested locally).
Here's the file where in which I try to instantiate the "Melodie" object:
#include <Melodie.h>
Melodie<5> m(8);
void setup()
{
}
void loop()
{
}
Here's the "Melodie.h" file:
#ifndef Melodie_H
#define Melodie_H
#include <Arduino.h>
#include "pitches.h"
template <int NB_NOTES>
class Melodie
{
public:
Melodie(int pin)
{
// Some unimportant stuff
}
void addNote(int pitch, int duration)
{
// Some unimportant stuff
}
void play()
{
// Some unimportant stuff
}
private:
char notes_[NB_NOTES];
char durations_[NB_NOTES];
int notePointer_;
int pin_;
};
#endif
I get the following error message:
error: expected constructor, destructor, or type conversion before '<' token
Why? The same code works(minus arduino specific stuff) works in Visual Studio. I thought WinAVR supported C++?
I tried and compiled your code (GCC) without problem with two minor modifications.
Change #include <Melodie.h> to #include "Melodie.h"
comment out the following
//#include <Arduino.h>
//#include "pitches.h"
since they are not used.