I have a C++/Win32/MFC project in Visual Studio 2008, and I'm getting a strange error message when I compile it.
I've created a small project to demonstrate the problem, and the main code is
#ifndef _MyObject_h
#define _MyObject_h
class MyObject
{
public:
MyObject()
{
}
};
#endif // _MyObject_h
// --- END MyObject.h
// --- BEGIN ObjectData.h
#ifndef _ObjectData_h
#define _ObjectData_h
template <typename DataPolicy>
class ObjectData
{
public:
DataPolicy *data;
ObjectData() :
data(NULL)
{
}
ObjectData(const ObjectData<DataPolicy> ©) :
data(copy.data)
{
}
ObjectData<DataPolicy> & operator=(const ObjectData<DataPolicy> ©)
{
this->data = copy.data;
return *this;
}
};
#endif // _ObjectData_h
// --- END ObjectData.h
// --- BEGIN Tool.h
#ifndef _Tool_h
#define _Tool_h
#include "ObjectData.h"
template <typename ObjectPolicy>
class Tool
{
private:
ObjectData<typename ObjectPolicy> _object;
public:
Tool(ObjectData<typename ObjectPolicy> obj);
};
#endif // _Tool_h
// --- END Tool.h
// --- BEGIN Tool.cpp
#include "stdafx.h"
#include "Tool.h"
template <typename ObjectPolicy>
Tool<ObjectPolicy>::Tool(ObjectData<typename ObjectPolicy> obj) :
_object(obj)
{
}
// --- END Tool.cpp
// --- BEGIN Engine.h
#ifndef _Engine_h
#define _Engine_h
#include "Tool.h"
#include "MyObject.h"
class Engine
{
private:
MyObject *_obj;
public:
Engine();
~Engine();
void DoSomething();
};
#endif // _Engine_h
// --- END Engine.h
// --- BEGIN Engine.cpp
#include "stdafx.h"
#include "Engine.h"
Engine::Engine()
{
this->_obj = new MyObject();
}
Engine::~Engine()
{
delete this->_obj;
}
void Engine::DoSomething()
{
ObjectData<MyObject> objData;
objData.data = this->_obj;
// NEXT LINE IS WHERE THE ERROR OCCURS
Tool< ObjectData<MyObject> > *tool = new Tool< ObjectData<MyObject> >(objData);
}
// --- END Engine.cpp
Errors:
Engine.cpp
c:\projects\myproject\myproject\engine.cpp(18) : error C2664: 'Tool::Tool(ObjectData)' : cannot convert parameter 1 from 'ObjectData' to 'ObjectData'
with
[
ObjectPolicy=ObjectData,
DataPolicy=ObjectData
]
and
[
DataPolicy=MyObject
]
and
[
DataPolicy=ObjectData
]
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>Build log was saved at "file://c:\Projects\MyProject\MyProject\Debug\BuildLog.htm"
MyProject - 1 error(s), 0 warning(s)
Thanks for any help.
There are a few problems with your code. First of all, you are using the typename keyword in a wrong way. typename can be used only when qualified type names are used (and is required when the type names are dependent), which is not your case:
template <typename ObjectPolicy>
class Tool
{
private:
ObjectData<typename ObjectPolicy> _object; // "typename" is not needed!
public:
Tool(ObjectData<typename ObjectPolicy> obj); // "typename" is not needed!
};
The problem you complain about, however, is in your instantiation of the Tool class template:
Tool< ObjectData<MyObject> > *tool = new Tool< ObjectData<MyObject> >(objData);
Your Tool<> template contains a member variable of type ObjectData<ObjectPolicy>, where ObjectPolicy is the class template parameter. However, in the line above you instantiate Tool with ObjectData<MyObject> as a parameter. This means your member variable will have type ObjectData<ObjectData<MyObject>>, and this will also be the type of the constructor's parameter.
Because of this, you are trying to invoke a constructor which accepts an ObjectData<ObjectData<MyObject>> with an argument of a mismatching type ObjectData<MyObject>. Hence, the error you get.
You should change your instantiation into:
Tool< MyObject > *tool = new Tool< MyObject >(objData);
Another problem is that you have the definition of Tool's member functions in a separate .cpp files. You should not do that: the linker won't be able to see it when processing a separate translation unit.
To solve this problem, put the definitions of your class template's member functions into the same header where the class template is defined (Tool.h in your case).
Tool< ObjectData<MyObject> > *tool = new Tool< ObjectData<MyObject> >(objData);
template <typename ObjectPolicy>
Tool<ObjectPolicy>::Tool(ObjectData<typename ObjectPolicy> obj) :
_object(obj)
{
}
It seems to me you might not really understand how templates work.
Check out the following C++ Templates
What you currently have is invalid C++ syntax. Take a look and give it another shot.
Related
I have a header class that looks like this:
#ifndef A_H__
#define A_H__
using namespace pcl::tracking;
namespace ball_tracking_cloud
{
template <typename PointType>
class OpenNISegmentTracking
{
public:
//...
protected:
void update(const sensor_msgs::PointCloud2ConstPtr &input_cloud);
}; // end of class
} // end namespace
#endif
And now I have a .cpp file that looks like this:
#include <ball_tracking_cloud/particle_detector.h>
bool init = true;
namespace ball_tracking_cloud
{
void OpenNISegmentTracking<pcl::PointXYZRGBA>::update(const sensor_msgs::PointCloud2ConstPtr &input_cloud)
{
pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGBA>);
pcl::fromROSMsg(*input_cloud, *cloud);
if(init)
{
v.run ();
init=false;
}
v.cloud_cb(cloud);
}
} // end of namespace
If I compile my code I get this error:
: error: specializing member ‘ball_tracking_cloud::OpenNISegmentTracking<pcl::PointXYZRGBA>::update’ requires ‘template<>’ syntax
void OpenNISegmentTracking<pcl::PointXYZRGBA>::update(const sensor_msgs::PointCloud2ConstPtr &input_cloud)
^
/hri/localdisk/markus/ros-alex/src/ball_tracking/ball_tracking_cloud/src/particle_detector.cpp:38:1: error: expected ‘}’ at end of input
} // end of namespace
^
I am not sure why I get this error..... I guess it has something to do with the fact that I use a template class ..... but I am not sure about this....
Any help would be great!
Your OpenNISegmentTracking is what in c++ terms is called a full template specialization.
In other words, it's a version of your template that will be invoked, only when the template parameter is a pcl::PointXYZRGBA.
The proper syntax for such a definition is
template <>
void OpenNISegmentTracking<pcl::PointXYZRGBA>::update(const sensor_msgs::PointCloud2ConstPtr &input_cloud)
{
...
}
You need this syntax for the function name:
template<>
void OpenNISegmentTracking<pcl::PointXYZRGBA>::update(const sensor_msgs::PointCloud2ConstPtr &input_cloud)
{
// ...
}
I have an Array class that is inheriting from BaseArray class. In BaseArray, I have the protected member variables data_ and cur_size_. The Array class introduces a resize function. The problem I am encountering is that none of the protected member variables from BaseArray are seeming to be accessed in the resize function.
EDIT: Solved the max_size_ problem, but the cur_size_ and data_ file persists
Inheritance? Scope? Help?
The Error:
In file included from Array.h:41:0,
from driver.cpp:6:
Array.cpp: In member function ‘void Array<T>::resize(size_t)’:
Array.cpp:29:5: error: ‘data_’ was not declared in this scope
data_=data_;
^
Array.cpp:30:18: error: ‘cur_size_’ was not declared in this scope
if (new_size>cur_size_)
^
Array.cpp:37:5: error: ‘cur_size_’ was not declared in this scope
cur_size_=new_size;
^
The Code:
BaseArray.h:
#ifndef _BASEARRAY_H_
#define _BASEARRAY_H_
#include <cstring>
template <typename T>
class BaseArray
{
public:
/// Type definition of the element type.
typedef T type;
//constructors, destructor and methods…
protected:
/// Pointer to the actual data. m
char * data_;
/// Current size of the BaseArray.
size_t cur_size_;
};
#include "BaseArray.inl"
#include "BaseArray.cpp"
#endif // !defined _BASEARRAY_H_
Array.h:
#ifndef _ARRAY_H_
#define _ARRAY_H_
#include <cstring>
#include "BaseArray.h"
template <typename T>
class Array: public BaseArray<T> //inheriting from BaseArray
{
public:
/// Type definition of the element type.
typedef T type;
/// Default constructor.
Array (void);
Array (const Array & arr);
/// Destructor.
~Array (void);
const Array & operator = (const Array & rhs);
void resize (size_t new_size);
private:
size_t max_size_; //introduces max_size
};
#include "Array.inl"
#include "Array.cpp"
#endif // !defined _ARRAY_H_
Array.cpp:
#include "BaseArray.h"
#include "Array.h"
#include <stdexcept>
#include <iostream>
template <typename T>
Array <T>::Array (void): BaseArray<T>()
{
std::cout<<"Array def const called"<<std::endl;
}
template <typename T>
Array <T>::Array (const Array & array): BaseArray<T>(array)
{
}
template <typename T>
Array <T>::~Array (void)
{
}
template <typename T>
void Array <T>::resize (size_t new_size)
{
this->data_= this->data_;
if (new_size>this->cur_size_)
{
max_size_ = new_size-this->cur_size_-1;
this->cur_size_=new_size;
for (max_size_; max_size_<=new_size; max_size_++)
this->data_[max_size_]=0;
}
this->cur_size_=new_size;
}
/* Also tried it like this:
template <typename T>
void Array <T>::resize (size_t new_size)
{
BaseArray<T>::data_= BaseArray<T>::data_;
if (new_size>BaseArray<T>::cur_size_)
{
max_size_ = new_size-BaseArray<T>::cur_size_-1;
BaseArray<T>::cur_size_=new_size;
for (max_size_; max_size_<=new_size; max_size_++)
BaseArray<T>::data_[max_size_]=0;
}
BaseArray<T>::cur_size_=new_size;
} */
regarding the first error, you have no max_size() member declared in Array.
regarding the second error, name lookup in templates follows a two stage logic, where non dependent expressions are looked up at definition point, whereas dependent expressions are looked up at instantiation point;
This means that when the compiler sees data_ it thinks it's a variable located somewhere else; at best, it won't find it giving you an error, at worst, it will give you the wrong variable !
In order to solve the problem, you need to make that a dependent expression, the most obvious way being replacing all data_ with this->data_, etc...
regarding your code organization, define your templates into a single header file; if you really want to split member implementations place them in a single file with a sensible file extension ( inl is ok, cpp is not )...
With the below code:
materia.h:
#ifndef MATERIA_H
#define MATERIA_H
class material
{
public:
template <class type>
static material* MakeMaterial(typename type::configtype, long);
template <class type>
void CreateNaturalForm(typename type::configtype, long);
…
};
template <class type>
material* material::MakeMaterial(typename type::configtype Config, long Volume)
{
return type::Spawn(Config, Volume);
}
#endif
materias.h:
#ifndef MATERIAS_H
#define MATERIAS_H
#include "materia.h"
#include "confdef.h"
class solid : public material {
public:
typedef solidmaterial configtype;
…
};
template material* material::MakeMaterial<solid>(solidmaterial, long);
template <class type>
void material::CreateNaturalForm(typename type::configtype Config, long Volume)
{
…
MakeMaterial(Config, Volume); // Error here
…
}
template void material::CreateNaturalForm<solid>(solidmaterial, long);
#endif
confdef.h:
#ifndef CONFDEF_H
#define CONFDEF_H
enum solidmaterial {
WOOD,
…
};
#endif
main.cpp
#include "materia.h"
#include "materias.h"
#include "confdef.h"
int main()
{
material::MakeMaterial(WOOD, 500); // Same error here
}
(Here's an online version of the above code that reproduces the error.)
I get the following compilation error message on the commented line:
No matching function for call to 'MakeMaterial'
What am I doing wrong? Shouldn't the explicit instantiation allow the compiler to see the correct function?
The code compiles if I write MakeMaterial<solid> explicitly, but the whole point here is to deduce type from the Config argument. How can I achieve this?
In the call
MakeMaterial(Config, Volume); // Error here
the compiler is asked to find a match where type::configtype in the function template, is the type of Config.
But nothing tells the compiler what to match type to: this is not an explicit instantiation.
In general there could be hundreds of types that type could be matched to, where type::configtype would be the type of Config. C++ does not support the special case where there is only one such possible type.
How to fix that depends on what you meant to accomplish.
I want to use new C++11 feature 'extern template class' with STL-container of movable objects (NOT copyable) and get compiler errors.
Example:
MyFile.hpp
#pragma once
#include <cstdio>
class MyFile
{
std::FILE * handle;
public:
MyFile(const char * filename);
~MyFile();
MyFile(MyFile && that);
MyFile & operator=(MyFile && that);
MyFile(const MyFile&) = delete;
void operator=(const MyFile&) = delete;
std::FILE const * getFile() const;
};
MyFile.cpp:
#include "MyFile.hpp"
#include <iostream>
MyFile::MyFile(const char * filename)
: handle{nullptr}
{
if (!(handle = fopen(filename, "r")))
throw std::runtime_error("blah blah blah");
}
MyFile::~MyFile()
{
std::cout << "File::~File()" << std::endl;
if (handle)
fclose(handle);
}
MyFile::MyFile(MyFile && that)
: handle{nullptr}
{
*this = std::move(that);
}
MyFile & MyFile::operator =(MyFile && that)
{
std::swap(handle, that.handle);
return *this;
}
const std::FILE * MyFile::getFile() const
{
return handle;
}
FileDeque.hpp:
#pragma once
#include <deque>
#include "MyFile.hpp"
extern template class std::deque<MyFile>;
using FileDeque = std::deque<MyFile>;
FileDeque.cpp:
#include "FileDeque.hpp"
template class std::deque<MyFile>;
And the test program:
#include
using namespace std;
#include "MyFile.hpp"
#include "FileDeque.hpp"
int main()
{
cout << "Hello World!" << endl;
{
FileDeque files;
files.emplace_back("C:/eula.1028.txt");
files.emplace_back("C:/eula.1031.txt");
files.emplace_back("C:/eula.2052.txt");
}
return 0;
}
With Visual Studio 2013 I get the following error:
D:\WinPrograms\Microsoft Visual Studio 12.0\VC\INCLUDE\deque(1714) : error C2280: 'MyFile::MyFile(const MyFile &)' : attempting to reference a deleted function
d:\devel\unique_ptr3\MyFile.hpp(18) : see declaration of 'MyFile::MyFile'
D:\WinPrograms\Microsoft Visual Studio 12.0\VC\INCLUDE\deque(1682) : while compiling class template member function 'void std::deque>::_Insert_n(std::_Deque_const_iterator>>,unsigned int,const MyFile &)'
with
[
_Ty=MyFile
]
D:\WinPrograms\Microsoft Visual Studio 12.0\VC\INCLUDE\deque(1510) : see reference to function template instantiation 'void std::deque>::_Insert_n(std::_Deque_const_iterator>>,unsigned int,const MyFile &)' being compiled
with
[
_Ty=MyFile
]
d:\devel\unique_ptr3\FileDeque.hpp(7) : see reference to class template instantiation 'std::deque>' being compiled
with
[
_Ty=MyFile
]
Generating Code...
It is clear that compiler tries to instantiate std::deque>::_Insert_n function that uses copying of objects, but why?
If std::deque is used directly in main.cpp I get no errrors:
#include <iostream>
#include <deque>
using namespace std;
#include "MyFile.hpp"
using FileDeque = std::deque<MyFile>;
int main()
{
cout << "Hello World!" << endl;
{
FileDeque files;
files.emplace_back("C:/eula.1028.txt");
files.emplace_back("C:/eula.1031.txt");
files.emplace_back("C:/eula.2052.txt");
}
return 0;
}
Also tried with clang and gcc and get similiar errrors.
So my questions:
Is it possible to make compiler not to instantiate container's class of movable objects? Why compiler tryies to instantiate methods that require copying support?
Do I want something wrong?
C++11 [temp.explicit]/8 states:
An explicit instantiation that names a class template specialization is also an explicit instantiation of the same kind (declaration or definition) of each of its members (not including members inherited from base classes) that has not been previously explicitly specialized in the translation unit containing the explicit instantiation, except as described below.
Since some of the members of std::deque<foo> require a copyable type foo - at the very least, the copy constructor - instantiating them is ill-formed. This is the cause of the errors you observe.
The workaround for this is to explicitly instantiate only the well-formed members that your program uses, something like:
// in FileDeque.hpp:
// Uncomment this to get linker errors suggesting
// other members to explicitly instantiate:
// extern template class std::deque<MyFile>;
extern template std::deque<MyFile>::deque();
extern template std::deque<MyFile>::~deque();
extern template auto std::deque<MyFile>::begin() -> iterator;
extern template auto std::deque<MyFile>::end() -> iterator;
// ...
// in FileDeque.cpp:
template std::deque<MyFile>::deque();
template std::deque<MyFile>::~deque();
template auto std::deque<MyFile>::begin() -> iterator;
template auto std::deque<MyFile>::end() -> iterator;
// ...
Dear all, I've been stuck with this problem now for a few days and my searches were not successful.
What I am trying to do:
I want a template reader class (VariableReader) to handle different types of variables (usually unsigned int and pointers to vector).
I started with
#ifndef READER_H_
#define READER_H_
#include <string>
namespace BAT {
template <typename variableType = unsigned int>
class VariableReader {
public:
VariableReader<variableType>();
VariableReader<variableType>(std::string varName);
virtual ~VariableReader<variableType>();
std::string getVariableName();
void setVariableName(std::string varName);
bool isValidVariableName(std::string varName);
variableType getVariable();
private:
std::string variableName;
variableType variable;
};
}
#endif
and
#include "../../interface/Readers/VariableReader.h"
namespace BAT {
template<typename variableType>
VariableReader<variableType>::VariableReader() :
variableName("") {
// TODO Auto-generated constructor stub
}
template <typename variableType>
VariableReader<variableType>::VariableReader(std::string varName) :
variableName(varName) {
}
template <typename variableType>
std::string VariableReader<variableType>::getVariableName() {
return variableName;
}
template <typename variableType>
void VariableReader<variableType>::setVariableName(std::string varName) {
if (VariableReader::isValidVariableName(varName)) {
variableName = varName;
}
}
template <typename variableType>
bool VariableReader<variableType>::isValidVariableName(std::string varName) {
return varName != "";
}
template <typename variableType>
VariableReader<variableType>::~VariableReader() {
// TODO Auto-generated destructor stub
}
}
However, although it seems to compile I can't use it within other projects.
EDIT: forgot to post test-code:
#include "cute.h"
#include "ide_listener.h"
#include "cute_runner.h"
#include "Readers/VariableReader.h"
using namespace BAT;
static VariableReader<int> *reader;
void setUp(){
reader = new VariableReader<int>::VariableReader();//this is problem-line
}
void thisIsATest() {
ASSERTM("start writing tests", false);
}
void runSuite(){
cute::suite s;
//TODO add your test here
s.push_back(CUTE(thisIsATest));
cute::ide_listener lis;
cute::makeRunner(lis)(s, "The Suite");
}
int main(){
runSuite();
}
I get following error message:
Building target: BAT_Tests
Invoking: GCC C++ Linker
g++ -L"/workspace/BAT/Debug Gcov" -fprofile-arcs -ftest-coverage -std=c99 -o"BAT_Tests" ./src/Test.o -lBAT
./src/Test.o: In function `setUp()':
/workspace/BAT_Tests/Debug Gcov/../src/Test.cpp:13: undefined reference to `BAT::VariableReader<int>::VariableReader()'
collect2: ld returned 1 exit status
make: *** [BAT_Tests] Error 1
As I understand it the linker tries to find the constructor for VariableReader, which is not explicitly defined since I want to have a general constructor only.
Please help me to understand what I am missing.
The C++ FAQ Lite section on How can I avoid linker errors with my template functions? shows two solutions:
Move the template class's methods into the .h file (or a file included by the .h file).
Instantiate the template in the .cpp file using template VariableReader<unsigned int>;.
The constructor(s) and destructor doesn't need the template arguments in it. In addition, template classes must have the full source available to compile- you can't declare the members and define them in another translation unit like you can with normal classes.