This question already has an answer here:
Why class data members can't be initialized by direct initialization syntax?
(1 answer)
Closed 2 years ago.
In C++ I am having trouble passing parameters to the constructor for a template class.
it works when I instantiate from a function; but if I instantiate from a class, it gives "error C2059: syntax error: 'string'"
this is my very trimmed down example (names have been changed to protect the incent).
I am currently have std:latest enabled in Visual Studio 2019 and I've tried in 2017 as well.
#include <string>
#include <iostream>
template <class T>
class cap
{
public:
cap() : p(new(T)) {}
cap(const std::string& sfile, const std::string& sfunc, int line)
: m_file(sfile), m_func(sfunc), m_line(line) {}
~cap() {
delete p;
std::cout << "object freed: created in " << m_func << " line " << m_line << " of " << m_file;
}
private:
T* p{nullptr};
std::string m_file;
std::string m_func;
int m_line{0};
};
void foo()
{
cap<int> foo1("file", "func", 5); //<< compiles okay
}
class bar
{
cap<int> foo1("file", "func", 5); //<< "syntax error: 'string'"
};
IntelliSense says "expected a type specifier" when I hover the params used inside the class
My end goal is to have a macro to instantiate the object; passing in the location in source.The object thus knows where it was created.
#define CAP(type,var) cap<type> var(__FILE__, __func__, __LINE__)
CAP(somestruct, myvar);
// expands to:
cap<somestruct> myvar("file.cpp", "myfunc", 50);
For in-class initialization use the uniform initialization:
class bar
{
cap<int> foo1{"file", "func", 5};
};
#Alan has already provided a reference for why direct initialization using () don't work. It's also known as the C++ most vexed parse.
Related
I am building my program by using the latest Emscripten compiler.
It is based on Clang version 14. Actually it is a small test program which is the following:
#include <iostream>
struct Test {
template<typename T>
static inline void Dump(const T& value) {
std::cout << "[generic] = '" << value << "'\n";
}
template<>
static inline void Dump<std::string>(const std::string& value) {
std::cout << "[std::string] = '" << value << "'\n";
}
};
int main() {
std::string text = "hello";
Test::Dump(text);
return 0;
}
When I build it by Emscripten compiler I got the warning:
D:\em_test>emcc a.cpp
a.cpp:10:24: warning: explicit specialization cannot have a storage class
static inline void Dump<std::string>(const std::string& value) {
~~~~~~~ ^
1 warning generated.
If I just remove static keyword from void Dump<std::string> line
then there will be no warning. However, this code will cause compilation error in Visual Studio:
D:\em_test\a.cpp(17,11): error C2352: 'Test::Dump': illegal call of non-static member function
But this error is expected and clear.
I would like to write a cross-platform program.
So, I think I should simple disable this warning in Emscripten.
However, I can not find any Emscripten (which is based on clang version 14)
command line option for that!
And I am asking advice for that.
Actually I tried to use -Wno-static-inline-explicit-instantiation command line option but it did not help:
D:\em_test>emcc -Wno-static-inline-explicit-instantiation a.cpp
a.cpp:10:24: warning: explicit specialization cannot have a storage class
static inline void Dump<std::string>(const std::string& value) {
~~~~~~~ ^
1 warning generated.
However, I see in Clang version 13 user manual description about -Wstatic-inline-explicit-instantiation option but it is about a slightly another warning text.
Also it seems that Clang version 14 is not fully released, so, there is no public Clang version 14 user manual.
I can not find any Emscripten or Clang command line option to disable the above warning.
Could somebody help me?
Explicit specialization of (both static and non-static) function templates cannot be put into class definitions.
Just put it into the enclosing namespace(i.e somewhere after the class):
#include <iostream>
struct Test {
template <typename T>
static inline void Dump(const T& value) {
std::cout << "[generic] = '" << value << "'\n";
}
};
// Notice Test::
template <>
inline void Test::Dump<std::string>(const std::string& value) {
std::cout << "[std::string] = '" << value << "'\n";
}
int main() {
std::string text = "hello";
Test::Dump(text);
return 0;
}
inline is never necessary for in-class function definitions but it has different meaning for member variables.
inline for out-class is necessary in header files because the explicit specialization is not a template anymore.
I am trying to convert boost::object_pool usage on my old project to new visual studio 2019 project, I am using boost version 1.56
ObjectPool.h
class BOOST_OBJECT_POOL_CHECKER
{
boost::object_pool< T > m_sObjectPool;
template <class Arg1>
T* contruct(Arg1& sArg1)
{
T* temp = m_sObjectPool.construct(sArg1);
return temp;
}
}
MaterialServer.h
class MaterialServer
{
MaterialServer(dword serviceType, std::string path);
Material* NEW_MATERIAL();
}
Material.h
class Material
{
BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;
Material(MaterialServer* pMatServer);
}
Material.cpp
Material* MaterialServer::NEW_MATERIAL()
{
//Material* returnMaterial = m_poolMATERIAL.construct(this); << error on vs2019, not correct parameter
Material* returnMaterial = m_poolMATERIAL.construct(*this);
}
got first error
boost_1_56\boost\pool\detail\pool_construct_simple.ipp(19,1): error C2664: 'Material::Material(MaterialServer*)': cannot convert argument 1 from 'const T0' to 'MaterialServer *'
ObjectPool.h(68): message : see reference to function template instantiation 'Material *boost::object_pool<T,boost::default_user_allocator_new_delete>::construct<Arg1>(const T0 &)' being compiled
with
[
T=Material,
Arg1=MaterialServer,
T0=MaterialServer
]
should I need upgrade boost version? because previously this code compiled fine on vs2008, but not compiled on vs2019, this c++11 standard so confusing for me
can I get explanation this behavior?
Frankly, this code cannot have compiled under any compiler.
Note: I'm ignoring numerous typos, omitted semi-colons, omitted template declarators, typedefs and access specifiers to focus on the real issues.
You're passing *this which is Material&. However, the contruct [sic] function takes a MaterialServer*.
So, in fact, the commented line was closer, and makes sense IFF it were a member of MaterialServer, not Material.
It would make a lot more sense, logically, for the material server to "create new materials", anyways, and almost works:
class Material {
public:
Material(MaterialServer* pMatServer);
};
class MaterialServer {
BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;
public:
MaterialServer(dword serviceType, std::string path);
Material* NEW_MATERIAL();
};
Material* MaterialServer::NEW_MATERIAL()
{
Material* returnMaterial = m_poolMATERIAL.construct(this);
return returnMaterial;
}
I say /almost/ because construct takes its argument by mutable reference. That won't compile here (this is NOT a mutable lvalue).
So, fixing that:
template <typename Arg1> T* construct(Arg1 sArg1) {
return m_sObjectPool.construct(sArg1);
}
Or, more generically:
template <typename... Arg> T* construct(Arg&&... sArg) {
return m_sObjectPool.construct(std::forward<Arg>(sArg)...);
}
We get "compiling code". We can't link it (the constructors aren't defined).
Adding some more imagined code:
Live On Coliru
#include <boost/pool/object_pool.hpp>
#include <iomanip>
#include <iostream>
#include <string>
#include <atomic>
using dword = uint32_t;
template <typename T> class BOOST_OBJECT_POOL_CHECKER {
boost::object_pool<T> m_sObjectPool;
public:
template <typename... Arg> T* construct(Arg&&... sArg)
{
return m_sObjectPool.construct(std::forward<Arg>(sArg)...);
}
};
class MaterialServer; // forward declare
class Material {
public:
Material(MaterialServer* pMatServer);
};
class MaterialServer {
BOOST_OBJECT_POOL_CHECKER<Material> m_poolMATERIAL;
dword _serviceType;
std::string _path;
public:
MaterialServer(dword serviceType, std::string path)
: _serviceType(serviceType)
, _path(path)
{
}
Material* NEW_MATERIAL();
dword getServiceType() const { return _serviceType; }
std::string_view getPath() const { return _path; }
};
Material* MaterialServer::NEW_MATERIAL()
{
Material* returnMaterial = m_poolMATERIAL.construct(this);
return returnMaterial;
}
Material::Material(MaterialServer* pMatServer)
{
static std::atomic_int id{0};
std::cout << "Material " << id++ << " from server ("
<< pMatServer->getServiceType() << ", "
<< std::quoted(pMatServer->getPath()) << ")\n";
}
int main() {
MaterialServer a(123, "Material/a/resource");
MaterialServer b(234, "Material/b/resource");
a.NEW_MATERIAL();
a.NEW_MATERIAL();
b.NEW_MATERIAL();
a.NEW_MATERIAL();
}
Prints
Material 0 from server (123, "Material/a/resource")
Material 1 from server (123, "Material/a/resource")
Material 2 from server (234, "Material/b/resource")
Material 3 from server (123, "Material/a/resource")
This question already has answers here:
default parameters in .h and .cpp files [duplicate]
(4 answers)
Closed 4 years ago.
Why are my default/optional parameters being ignored?
grid_model.h
class GridModel {
public:
GridModel();
void PrintGrid(bool);
};
grid_model.cpp
void GridModel::PrintGrid(bool flag = false) {
// things...
}
grid_model_test.cpp
ns::GridModel* gm = new GridModel();
gm->PrintGrid(true); // works
gm->PrintGrid(); // doesn't work
error:
grid_model_test.cpp:22:12: error: no matching function for call to ‘ns::GridModel::PrintGrid()’
gm->PrintGrid();
^
In file included from grid_model_test.cpp:2:0:
grid_model.h:27:7: note: candidate: void ns::GridModel::PrintGrid(bool)
void PrintGrid(bool);
^~~~~~~~~
When I use them elsewhere, they seem to work fine.
#include <iostream>
class Thing {
public:
void Whatever(bool);
};
void Thing::Whatever(bool flag = false) {
std::cout << "Parameter was: " << flag << std::endl;
}
int main() {
Thing* thing = new Thing();
thing->Whatever();
return 0;
}
Default parameter values should, as a good design practice, be placed in the declaration, not in the implementation:
class GridModel {
public:
GridModel();
void PrintGrid(bool flag=false);
};
void GridModel::PrintGrid(bool flag) {
// things...
}
Technically (as described in more length here http://en.cppreference.com/w/cpp/language/default_arguments ): the default arguments must be visible in the translation unit where the call is made. If you split the class in a grid_model.h and grid_model.cpp, any other .cpp (such as grid_model_test.cpp) that includes grid_model.h will not be aware of information that is only present in grid_model.cpp.
I am facing compilation problem while running the following program:
I am calling non template member function inside template member function but getting the weird compilation errors.
#include <iostream>
#include <boost\shared_ptr.hpp>
class base
{
public:
base()
{
}
void fun2(boost::shared_ptr<int> &data)
{
std::cout << "This is fun2" << std::endl;
}
void fun3(boost::shared_ptr<double> &value)
{
std::cout << "This is fun3" << std::endl;
}
template <typename T>
void fun1(int switchParam,T &resonse)
{
std::cout << "This is fun1." << std::endl;
switch(switchParam)
{
case 0:
fun2(resonse);
break;
case 1:
fun3(resonse);
break;
}
}
};
void main()
{
boost::shared_ptr<int> myInt;
int switchParam = 0;
base b1;
b1.fun1(switchParam,myInt);
}
Getting the following compilation problem:
Error 1 error C2664: 'base::fun3' : cannot convert parameter 1 from 'boost::shared_ptr<T>' to 'boost::shared_ptr<T> &'
Any help will be appreciated.
No. You cannot do that. With second phase of template code compilation for any type the switch block has to be fully compiled by compiler. It will will fail to compile. You are mixing templates with runtime behavior of program. You better write a different function.
Note that switch is runtime, not compile time. When you call it as fun1(0) the compiler still has to compile it fully for int. It won't evaluate runtime switch statement and eliminate fun3, which takes shared_ptr<double>.
This question already has answers here:
visual studio implementation of "move semantics" and "rvalue reference"
(2 answers)
Closed 7 years ago.
So I'm trying to pass a std::unique_ptr as a parameter to a function that is launched in a separate thread, and I'm getting a strange error at compile time that reads:
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(1149): error C2280: 'std::unique_ptr<Widget,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function
A simplified version of this code, that still reproduces the same issue is:
#include <thread>
#include <memory>
#include <iostream>
class Widget
{
public:
Widget() : m_data(0)
{
}
void prepareData(int i)
{
m_data = i;
}
int getData() const
{
return m_data;
}
private:
int m_data;
};
void processWidget(std::unique_ptr<Widget> widget)
{
std::cout << widget->getData() << std::endl;
}
int main()
{
std::unique_ptr<Widget> widget(new Widget());
widget->prepareData(42);
std::thread t(processWidget, std::move(widget));
t.join();
return 0;
}
My guess is that there is something wrong with the destruction of the Widget object from main(), however I cannot pinpoint the issue. Is it necessary to do something additional to cleanup that variable? By the way, I'm using VS2013.
You are not allowed to make copy of unique_ptr, therefore the copy constructor is disabled. That is pointing the compiler error.
You can fix it with a reference:
void processWidget(std::unique_ptr<Widget>& widget)