When I try to compile this with Clang
template<class T>
struct Field
{
char const *name;
Field(char const *name) : name(name) { }
};
template<class Derived>
class CRTP { static Field<Derived> const _field; };
class Class : public CRTP<Class> { };
Field<Class> const CRTP<Class>::_field("blah");
int main() { }
I get
error: template specialization requires 'template<>'
Field<Class> const CRTP<Class>::_field("blah");
~~~~~~~~~~~ ^
I don't understand the error at all. What is wrong with my definition of _field and how do I fix it?
(Note that the arguments to _field are not necessarily the same for all subclasses.)
For the compiler to identify this as a template specialization (e.g. to be able to check the syntax), you need the template keyword:
template<>
Field<Class> const CRTP<Class>::_field("blah");
Its brackets are empty as all template parameters are specialized, but you cannot just leave it away.
The error says exactly what is missing. template<> is missing before that line.
template<>
Field<Class> const CRTP<Class>::_field("blah");
Note, however, that your typing of Field<Class>, if unique, could be used to construct all instances of Field<Class> with a given string.
template<typename T>
struct field_trait;
template<class T>
struct Field
{
char const *name;
Field() : name(field_trait<T>::get_name()) {}
};
template<class Derived>
class CRTP { static Field<Derived> const _field; };
template<class Derived>
class CRTP<Derived>::_field;
class Class;
template<>
struct field_traits<Class> {
static const char* get_name() { return "blah"; }
};
class Class : public CRTP<Class> { };
int main() { }
which means that every instance of Field<Class> always has the name "blah".
One question I would have is, do you really need storage for said Field<Class> to actually have a pointer to a string, and if so does it need to be unique, and if so does it need to be "bare"? Because figuring out where the static instance exists is somewhat annoying.
Together with field_traits above:
template<class Derived>
class CRTP { static Field<Derived>& field() const { static Field<Derived> _field( field_traits<Derived>::get_name()); return _field; };
this moves the problem of "where is the _field stored" to being the compilers problem. And it is initialized by the contents of field_traits<T>::get_name().
A static data member must have both a declaration and a definition. If this was a plain class it would look like this:
// header:
class C {
static int i;
};
// source:
int C::i = 3;
Templates aren't ordinarily defined in source files, so the code would look something like this:
// header:
template <class T>
class C {
static int i;
};
template <class T>
int C<T>::i = 3;
In your code, you don't have the definition of the static data member. That's okay if you don't use it. But the code that the compiler is complaining about defines a static data member for CRTP<Class>; that's a specialization (because it's not applicable to all instantiations of CRTP, just to this one), and the compiler is saying that you have to tell it that it's a specialization. So do as you're told:
template <>
Field<Class> const CRTP<Class>::_field("blah");
or, to write the non-specialized template version, use the usual template syntax:
template <class T>
Field<T> const CRTP<T>::_field("blah");
Related
I write a template class dependent on a given type and variadic types, like so:
template<typename ConstType,typename...Inputs>
class ConstantTensor;
Then I write another class, which is generally defined in this way (assume wrong_type whatever type you want, but which is different from the following specialization ):
template<typename T>
class X{
public:
using type=wrong_type;
}
And I also have a specialization of this kind:
template<typename ConstType,typename...Inputs>
class X< ConstantTensor< ConstType ,Inputs...>>
{
public:
using type=right_type;
}
My problem is that, if I define the type ConstantTensor<ConstType,double> and then I want to use X<ConstantTensor<ConstType,double>>::type, the general case is called and not the specialization. So I obtain wrong_type instead of right_type. I guess it has to deal with the double type...Could you explain me why and how can I solve this issue? Thank you in advance.
EDIT:
Here a snippet of code, I hope it works:
class Scalar
{};
template<typename ConstType,typename...Inputs>
class ConstantTensor
{
public:
constexpr ConstantTensor(const Inputs&...inputs)
{}
};
template<typename ConstType,typename...Inputs>
constexpr auto Constant(const Inputs&...inputs)
{return ConstantTensor<ConstType,Inputs...>(inputs...);}
template<typename T>
class X{
public:
using type=int;
};
template<typename ConstType,typename...Inputs>
class X<ConstantTensor<ConstType,Inputs...>>{
public:
using type=char;
};
int main()
{
constexpr auto delta=Constant<Scalar>(2.0);
using type= X<decltype(delta)>::type; // this is int not char
}
The problem is that
constexpr auto delta=Constant<Scalar>(2.0);
is a constexpr variable; so it's also const.
So decltype(delta) isn't ConstantTensor<Scalar> but is a ConstantTensor<Scalar> const.
You can verify adding const in partial specialization declaration
template<typename ConstType,typename...Inputs>
class X<ConstantTensor<ConstType,Inputs...> const>{ // <-- added const
public:
using type=char;
};
Now you get that type is char.
-- EDIT --
The OP asks
Is there a short/elegant way to deal with both cases, const and non const, without duplicating the code?
I don't know if it's elegant, but it seems to me short enough: you can use a sort of self-inheritance adding the following partial specialization.
template <typename T>
class X<T const> : public X<T>
{ };
So X<ConstantTensor<Scalar> const> inherit from X<ConstantTensor<Scalar>>.
I am trying to compile the below code, and I am getting the error as
"error: ‘MD5Sum’ is not a class template
template<> struct MD5Sum<::cv_bridge::CvImage>"
template<> struct MD5Sum<::cv_bridge::CvImage>
{
static const char* value() { return MD5Sum<::sensor_msgs::msg::Image>::value(); }
static const char* value(const ::cv_bridge::CvImage&) { return value(); }
static const uint64_t static_value1 = MD5Sum<::sensor_msgs::msg::Image>::static_value1;
static const uint64_t static_value2 = MD5Sum<::sensor_msgs::msg::Image>::static_value2;
// If the definition of sensor_msgs/Image changes, we'll get a compile error here.
ROS_STATIC_ASSERT(MD5Sum<::sensor_msgs::msg::Image>::static_value1 == 0x060021388200f6f0ULL);
ROS_STATIC_ASSERT(MD5Sum<::sensor_msgs::msg::Image>::static_value2 == 0xf447d0fcd9c64743ULL);
};
This seems to be template specialization. Does it means that template class should be present first before make template specialization out of it.
The class template MD5Sum needs to be declared before any of its specializations.
You either need to include the file where the template is declared, or declare it yourself.
You can use an empty definition (if you only want to call fully specialized versions) or the generic implementation you choose:
// add this before your specialization
template <class T> struct MD5Sum; // empty declaration
// or your default implementation
template <class T> struct MD5Sum {
...
};
I have a template class as below:
template<typename A> struct TaskInfo{
typedef A _A;
static void bar(A a){blah blah...} };
template <typename TaskInfo> class Task {
typedef typename TaskInfo::_A A;
bar(A a){
blah blah...
TaskInfo::bar(a);
}
}
and I have an object that has a collection of these classes:
using TaskInfoX= TaskInfo<int>; //ignore the bar implementation for the time being.
using TaskInfoY= TaskInfo<double>;
class TaskCollection(){
TaskCollection(){
auto Task1=new Task<TaskInfoX>;
auto Task2=new Task<TaskInfoY>;
Register(Task1);
Register(Task2);
}
Register(...);
}
I want to know if it is possible to define an enum list:
enum TaskEnum
{
Etask1,
Etask2
};
and a function getTask such that in my app I can have:
int main {
TaskCollection collection;
int testInt;
double testDouble;
collection.getTask(Etask1)->bar(testInt);
//collection.getTask(Etask1)->bar(testDouble); //want compile error.
collection.getTask(Etask2)->bar(testDouble);
}
I know that I can have CRTP or the virtual inheritance equivalent that allows me to pass variadic arguments for bar() but I want to have type checking on the parameters of the bar function at compile time. Is this impossible in C++?
Update: Apologise for the typo. That was meant to be: getTask(task1). basically the outside world doesn't know about the underlying structure of the tasks and only knows them based on their public enum keys. Also note that in general there would be additional tasks potentially reusing the typeInfoX parameter.
First, to have error if type is not an exact match, you may use the following:
template <typename T>
class Task
{
public:
using type = typename T::type;
void bar(type a) { T::bar(a); }
template <typename U>
std::enable_if_t<!std::is_same<std::decay_t<U>, type>::value>
bar(U&&) = delete;
};
Then, with some helpers:
template <TaskEnum> struct TaskMap;
template <> struct TaskMap<Etask1> { using type = Task<TaskInfoX>; };
template <> struct TaskMap<Etask2> { using type = Task<TaskInfoY>; };
Your collection could be something like:
class TaskCollection
{
public:
Task<TaskInfoX> taskX;
Task<TaskInfoY> taskY;
template <TaskEnum E>
typename TaskMap<E>::type&
getTask();
};
template <>
Task<TaskInfoX>& TaskCollection::getTask<Etask1>() { return taskX; }
template <>
Task<TaskInfoY>& TaskCollection::getTask<Etask2>() { return taskY; }
With final usage:
collection.getTask<Etask1>().bar(testInt);
collection.getTask<Etask1>().bar(testDouble);//error:call to deleted member function 'bar'
collection.getTask<Etask2>().bar(testDouble);
Demo
You can always template a concrete class with primitives. So instead of:
using TaskInfoX= TaskInfo<int>;
using TaskInfoY= TaskInfo<double>;
you can just have
template<> class Task<TaskEnum::Task1> : public TaskInfo<int>{}
template<> class Task<TaskEnum::Task2> : public TaskInfo<double>{}
and then define a template function:
template<TaskEnum taskE>
Task<taskE>* getTask() {}
You will need to derive template class Task from a base class so you can put it in a map, and you should define a map
std::map<TaskEnum,TaskBase*> taskMap;
and in getTask you can just do a static cast:
static_cast<Task<taskE>* >(taskBasePtr);
I think std::tuple is what you need:
auto my_tuple = std::make_tuple(Task<TaskInfoX>(), Task<TaskInfoY>());
std::get<Task<TaskInfoX>>(my_tuple).bar(12);
// actually, this is not an error because double can be convert to int
std::get<Task<TaskInfoX>>(my_tuple).bar(12.323);
Given the way Task1 and Task2 are stored in your TaskCollection class, I cant see an obvious way to implement getTask as a template, but you can overload it.
class TaskCollection
{
//...
Task<TaskInfoX> GetTask(Task<TaskInfoX> task)
{
return Task1;
}
Task<TaskInfoY> GetTask(Task<TaskInfoY> task)
{
return Task2;
}
};
If your real case works in with double and int then you need to supress the conversion from double to int in order to achieve this compile-time error...
//collection.getTask(Task1)->bar(testDouble); //want compile error.
one way to do this is to declare but not define a template version of bar in your TaskInfo
template<typename A> struct TaskInfo
{
static void bar(A a){blah blah...}
template<typename T> static void bar(T a); // deliberately not defined
//...
};
you still define your existing bar function for the type you do want to handle, but now, in the case that you want to fail, the compiler will try to call the template version of bar (with T as a double) in preference to calling the int version with a conversion from double to int. The resulting error in VS2015 is
error LNK2019: unresolved external symbol "public: static void __thiscall C::bar(double)
but if no code tries to call it then it doesn't matter that it is not defined an there is no error.
(It wasn't clear to me what the question was regarding the enum)
I am trying to write a template using the CRTP pattern. What I would like is for the template to access a static const in the templated class.
My template look like this in it's own header:
template <class T> foo {
static const int readValue = T::value
}
And I inherit from the template like this (in another header file):
class fooImpl: foo<fooImpl> {
static const int value = 42;
}
However, clang complains:
No member named 'value' in 'fooImpl'
I think I get the chicken and egg problem here. The template does not know the definition of fooImpl, and hence, cannot know that it has the member value when it is instantiated.
But how do I work around it? Is there a way to get the compile time propagation of the const value into the instantiated template?
The foo<fooImpl> base class is instantiated in the base-class list but fooImpl is an incomplete type at that point, and foo::value has not been declared yet.
You can move the definition of the static member later:
template <class T> struct foo {
static const int readValue;
};
class fooImpl: foo<fooImpl> {
static const int value = 42;
};
template<class T> const int foo<T>::readValue = T::value;
However, this won't allow you to use readValue as a compile-time constant in the body of foo.
I would like to access a template parameter outside of a class. I usually do this as follows:
template <class T>
class A
{
typedef typename T T;
}
A<int>::T;
I would like to be able to do the same for non-type template parameters. This doesn't work:
template <int T>
class A
{
typedef typename T T;
}
A<3>::T;
I will clarify why I need this. I want to define a second class as follows:
template <class C>
class B
{
static int func() {return C::T;}
}
B<A<3> >::func();
What is the correct way to do this?
Thank you very much.
That's because T is not a type name and you cannot typedef it. It is an int value and, if you want to access it as a static member of the class, you need a static member int. Seems like what you really want is this:
template <int T>
class A
{
public:
static const int x = T;
};
doSomething(A<5>::x);
It's a value, and not a type, so perhaps:
template <int T>
class A
{
static const int param = T;
};
And then you can access it as A<42>::param. Not that it helps much, unless A is itself used as a template parameter somewhere else.
in the second case, T is not a type, it's an int value. Therefore you should define it as a const int or static const int value.
template <int T>
class A {
static const int T = T;
};
Note that it is customary to use T for types (in particular when the template is monadic, since there is no ambiguity on the type), and other names for constants, usually a more meaningful name, for instance SIZE or preferably Size (all caps symbols are best used for macros).
template <int Param>
class A {
static const int param = Param;
};
See other SO questions (like this one) for the use of static const values in the context of a template definition.