all!
I want write a template structure, which will give me concrete name of a class based on enum. In details:
in .h file
#include "Mish.h"
#include "ReLU.h"
namespace a
{
namespace b
{
enum class ActivationEnum : size_t
{
Mish,
ReLU
};
template <ActivationEnum act>
struct Activation
{
};
template <>
struct Activation<ActivationEnum::Mish>
{
using aType = Mish;
};
template <>
struct Activation<ActivationEnum::ReLU>
{
using aType = ReLU;
};
} // raul namespace
}
Then I want to use it in code as:
void someF(..., ActivationEnum act)
{
...
OtherClass<Activation<act>::aType> bla;
...
}
I've faced with two problems:
Mish and ReLU are implemented in Mish.cpp and ReLU.cpp files in namespace a, includes are here, but I got errors syntax error: identifier 'ReLU' and syntax error: identifier 'Mish'. If I add forward declaration here such as namespace a { class Mish; class ReLU; ... } then everything is ok here.
No matter in function someF I receive invalid template argument for 'a::b::Activation', expected compile-time constant expression
What are the problems? How can I return different typenames based on enum? Thank you.
Related
I'm trying to understand how including works in C++. I have two questions about it. The first one is on how properly import the .h file. For example I created the following HashNode.h file:
namespace HashNode{
template<class Data>
class HashNode{
private:
Data data;
HashNode *next;
public:
explicit HashNode(const Data &data);
Data getKey();
~Node();
};
}
So in the HashNode.cpp file, it should like:
#include "HashNode.h"
using namespace HashNode;
template <class Data> // ~~~ HERE 1 ~~~
HashNode::HashNode(const Data &data) {//todo};
template <class Data> // ~~~ HERE 2 ~~~
Data* HashNode::getKey() {
//todo
}
HashNode::~Node() {
//todo
}
This way it works but do I have to include template <class Data> beside each function which uses Data? Why it does not recognize Data without including template <class Data>?
Also I have created the Hash.h file which should use the HashNode.h file:
#include "HashNode.h"
using namespace HashNode;
namespace Hash {
template <class Data>
class Hash {
typedef enum {
GOOD = 0,
BAD = -1,
BAD_ALLOC = -2
} Status;
private:
HashNode **hash;
int capacity;
int size;
public:
explicit Hash(int size);
Status insertData(const Data &data);
~Hash();
};
}
But I get the the following error: Can't resolve type 'HashNode'. Why it can't see the import?
In the Hash.cpp file I get Unused import statement for #include "HashNode.h". Why is that?
Also, what if I want to include private functions - should them be in the .h file or in the .cpp file?
The member functions of a template class are themselves also templates. Because of this, they need to be defined with any required template parameters and template type definitions.
About your second question, it has to do with namespaces. As I see it, having namespace and class under the same naming might cause you ambiguity. Although, everything seems to be fine on the structural side of the code. Try using #pragma once or some kind of guards to prevent this kind of issues.
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)
{
// ...
}
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.
Why can I compile the following:
typedef void OnSuccessSignature(PathFinderType::EdgePath);
but not this?:
using OnSuccessSignature = void(PathFinderType::EdgePath);
The second line gives a C2061: syntax error : identifier 'EdgePath'
In case it makes a difference, the relevant part of the class is defined as
class MapManager : public Service<MapManager>
{
public:
// Aliases.
using PathFinderType = AStar<Map::MapNodeType, WeightedEuclideanDistance<Map::MapNodeType>>;
using OnSuccessSignature = void(PathFinderType::EdgePath);
// ...
}
and AStar
template <typename TNode, typename THeuristic = EuclideanDistanceSqrd<TNode>>
class AStar : Detail::AStarHeap<TNode>
{
public:
// Aliases.
using EdgePath = list<typename TNode::EdgeType*>;
// ...
}
I've included the second header in the first.
I am working with the libMesh FEM library and am trying to develop a class (EqCore) that inherits from libMesh. This class will provide some additional features that are inherited again by a class that I want to actually use (MainEq).
The two functions, set_constant and get_constant, are causing the error below. These worked as shown with a different inheritance scheme (see Inheritance of template class with a template member function in C++). The difference with this problem is that now the template parameter (Type) is actually a class that gets inherited. Is this a dangerous practice?
I would appreciate any help getting this code working or finding an alternate method.
ERROR MESSAGES:
In member function ‘void EqCore::set_constant(std::string, ParamType)’:
test_libmesh.cpp:26:57: error: expected primary-expression before ‘>’ token
In member function ‘ParamType EqCore::get_constant(std::string)’:
/home/slaughter/Documents/programs/source/test_libmesh.cpp:31:76: error: expected primary-expression before ‘>’ token
PROGRAM:
//! \example test_libmesh.cpp
#include <string>
using std::string;
// libMesh includes
#include <libmesh.h>
#include <libmesh_common.h>
#include <equation_systems.h>
#include <transient_system.h>
#include <explicit_system.h>
#include <parameters.h>
#include <mesh.h>
using namespace libMesh;
// Fundamental behavior that will be used among many classes
template <typename Type> class EqCore : Type{
public:
// Class constructor
EqCore(EquationSystems& sys, string name) : Type(sys, name, 1){}
// A function for storing a constant value (causes error)
template<typename ParamType> void set_constant(std::string name, ParamType var){
Type::get_equation_systems().parameters.set<ParamType>(name) = var;
}
// A function for retrieving a constant value (causes error)
template<typename ParamType> ParamType get_constant(std::string name){
ParamType output = Type::get_equation_systems().parameters.get<ParamType>(name);
return output;
}
};
// A test class derived
class MainEq : public EqCore<ExplicitSystem>{
public:
// Constructor
MainEq(EquationSystems& sys) : EqCore(sys, "main"){ }
};
// Begin main function
int main (int argc, char** argv){
// Initialize libMesh and create an empty mesh
LibMeshInit init (argc, argv);
Mesh mesh;
// Test w/o any of the above classes
EquationSystems eq_sys(mesh);
eq_sys.parameters.set<double>("test1") = 1;
printf("Test 1: %f\n", eq_sys.parameters.get<double>("test1"));
// Test my class set/get functions
MainEq eq(eq_sys);
eq.set_constant<double>("test2", 2);
printf("Test 2: %f\n", eq.get_constant<double>("test2"));
}
Because you are inside a template, the compiler cannot determine that set is a template automatically during parse time, and it's assuming that set is a non-template, and hence the parse fails.
The solution is to explicitly inform the compiler that set is a member template, as such.
Type::get_equation_systems().parameters.template set<ParamType>(name) = var
In C++ Template Metaprogramming: Concepts, Tools, and Techniques from Boost and Beyond, by David Abrahams, Aleksey Gurtovoy (Amazon) it is explained as follows:
double const pi = 3.14159265359;
template <class T>
int f(T& x)
{
return x.convert<3>(pi);
}
T::convert might be a member function template, in which case the
highlighted code passes pi to a specialization of convert<3>. It
could also turn out to be a data member, in which case f returns
(x.convert < 3 ) > pi. That isn't a very useful calculation, but the
compiler doesn't know it.
The template keyword tells the compiler that a dependent name is a
member template:
template <class T>
int f(T& x)
{
return x.template convert<3>(pi);
}
If we omit template, the compiler assumes that x.convert does not
name a template, and the < that follows it is parsed as the less-than
operator.