I want a static constant, LIST_DELIMITER, defined in my class below. However, I can't figure out how to declare it with templates.
// MyClass.h
#pragma once
#include <boost/algorithm/string.hpp>
#include <vector>
class MyClass
{
public:
MyClass();
virtual ~MyClass();
template<class T>
void GetAsVectorOfValues(std::vector<T> values)
{
boost::split(values, value_, boost::is_any_of(LIST_DELIMITER));
}
private:
std::string value_;
static const std::string LIST_DELIMITER;
};
// MyClass.cpp
std::string MyClass::LIST_DELIMITER = ",";
I know there are similar question on stackoverflow but I can't seem to find what I'm looking for. One thing that is different in my case is that my whole class is not templated, just the single method.
You have to use the exact same declaration, including qualifiers:
const std::string MyClass::LIST_DELIMITER = ",";
^^^^^
There's no template involved in this static class member definition.
Related
I think I need some tutoring on templates, especially in conjunction with inheritance. I am well aware those two concepts don't play very well together.
We've wanted to get ride of clang tidy warnings, but I have no clue how to achieve it.
The abstracted code is below, please see https://godbolt.org/z/sPfx7Yhad to compile it.
The setting is, we have some abstract base class (Animal), and a specialized type (Dog).
A converter functionality can only be defined on the base class.
There is a templated reader class, which is templated with the actual specialized typed (Reader<Dog>).
However, clang-tidy complains when analyzing reader.h, as converter::convert is not known.
It's only known in main.cpp, by including converter.h before reader.h.
I have tried to forward declare the function by using template:
namespace converter
{
template<typename T>
void convert(const std::string& input, T& animal);
}
Which leads to linker errors, because now the linker is looking for a void convert(const std::string&, Dog&) implemenation, rather than using the void convert(cons std::string&, Animal&) overload. (see https://godbolt.org/z/x4cPfh6P4)
What can I do? How could I change the design to avoid the clang-tidy warning?
In general, I cannot add the actual includes to converter.h in reader.h, as that part is generic and the user shall be able to use the reader with their own types, by providing a custom converter functionality.
What I cannot change are classes Dog and Animal. They are autogenerated classes / libraries which we are using.
For anyone who is interested, the real world example can be found here https://github.com/continental/ecal/blob/master/samples/cpp/measurement/measurement_read/src/measurement_read.cpp
#include <string>
#include <iostream>
// animal.h
// class hierarchy with abstract base class
class Animal
{
public:
std::string name;
virtual std::string what() = 0;
};
// dog.h
class Dog : public Animal
{
public:
std::string what() override {return "dog";}
};
// animal_converter.h
// converting function
// #include <animal.h>
namespace converter
{
void convert(const std::string& input, Animal& animal)
{
animal.name = input;
}
}
// reader.h
// Templated class for reader functionality
template <typename T>
class Reader
{
public:
T read()
{
T output;
converter::convert("Anton", output);
return output;
}
};
// main.cpp
// #include dog.h
// #include animal_converter.h
// #include reader.h
int main()
{
Reader<Dog> reader;
std::cout << reader.read().name << std::endl;
}
Background
I have been learning how to implement the pimpl idiom using the newer c++11 method described by Herb Sutter at this page: https://herbsutter.com/gotw/_100/
I'm trying to modify this example by adding a member variable to the private implementation, specifically a std::string (although a char* has the same issue).
Problem
This seems to be impossible due to the use of a static const non-integral type. In-class initialization can only be done for integral types, but because it is static it can't be initialized in the constructor either.
A solution to this problem is to declare the private variable in the header file, and initialize it in the implementation, as shown here:
C++ static constant string (class member)
However, this solution does not work for me because it breaks the encapsulation I'm trying to achieve through the pimpl idiom.
Question
How can I hide a non-integral static const variable within the hidden inner class when using the pimpl idiom?
Example
Here is the simplest (incorrect) example I could come up with demonstrating the problem:
Widget.h:
#ifndef WIDGET_H_
#define WIDGET_H_
#include <memory>
class Widget {
public:
Widget();
~Widget();
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
#endif
Widget.cpp:
#include "Widget.h"
#include <string>
class Widget::Impl {
public:
static const std::string TEST = "test";
Impl() { };
~Impl() { };
};
Widget::Widget() : pimpl(new Impl()) { }
Widget::~Widget() { }
Compilation command:
g++ -std=c++11 -Wall -c -o Widget.o ./Widget.cpp
Note that this example fails to compile because the variable TEST cannot be assigned at declaration due to it not being an integral type; however, because it is static this is required. This seems to imply that it cannot be done.
I've been searching for previous questions/answers to this all afternoon, but could not find any that propose a solution that preserves the information-hiding property of the pimpl idiom.
Solution Observations:
In my example above, I was attempting to assign the value of TEST in the Impl class declaration, which is inside of Widget.cpp rather than its own header file. The definition of Impl is also contained within Widget.cpp, and I believe this was the source of my confusion.
By simply moving the assignment of TEST outside of the Impl declaration (but still within the Widget/Impl definition), the problem appears to be solved.
In both of the example solutions below, TEST can be accessed from within Widget by using
pimpl->TEST
Attempting to assign a different string into TEST, i.e.
pimpl->TEST = "changed"
results in a compiler error (as it should). Also, attempting to access pimpl->TEST from outside of Widget also results in a compiler error because pimpl is declared private to Widget.
So now TEST is a constant string which can only be accessed by a Widget, is not named in the public header, and a single copy is shared among all instances of Widget, exactly as desired.
Solution Example (char *):
In the case of using a char *, note the addition of another const keyword; this was necessary to prevent changing TEST to point to another string literal.
Widget.cpp:
#include "Widget.h"
#include <stdio.h>
class Widget::Impl {
public:
static const char *const TEST;
Impl() { };
~Impl() { };
};
const char *const (Widget::Impl::TEST) = "test";
Widget::Widget() : pimpl(new Widget::Impl()) { }
Widget::~Widget() { }
Solution Example (string):
Widget.cpp:
#include "Widget.h"
#include <string>
class Widget::Impl {
public:
static const std::string TEST;
Impl() { };
~Impl() { };
};
const std::string Widget::Impl::TEST = "test";
Widget::Widget() : pimpl(new Widget::Impl()) { }
Widget::~Widget() { }
Update:
I realize now that the solution to this problem is completely unrelated to the pimpl idiom, and is just the standard C++ way of defining static constants. I've been used to other languages like Java where constants have to be defined the moment they are declared, so my inexperience with C++ prevented me from realizing this initially. I hope this avoids any confusion on the two topics.
#include <memory>
class Widget {
public:
Widget();
~Widget();
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};
/*** cpp ***/
#include <string>
class Widget::Impl {
public:
static const std::string TEST;
Impl() { };
~Impl() { };
};
const std::string Widget::Impl::TEST = "test";
Widget::Widget() : pimpl(new Impl()) { }
Widget::~Widget() { }
You might want to consider making TEST a static function which returns a const std::string&. This will allow you to defined it inline.
You could also replace const by constexpr in your example and it will compile.
class Widget::Impl {
public:
static constexpr std::string TEST = "test"; // constexpr here
Impl() { };
~Impl() { };
};
Update:
Well, it seems that I was wrong... I always store raw string when I want constants.
class Widget::Impl {
public:
static constexpr char * const TEST = "test";
};
Depending on the usage pattern, it might be appropriate or not. If not, then define the variable as explained in the other answer.
I have an issue when trying to initialize static members of a static class template.
Basically, what I thought this approach would be useful for:
I have a lot of objects, which are of course all of the same Base type but they have differing object types. I just want to manipulate these objects, that's why I decided to use a static template as there are quite a number of different types these object can consist of.
However, for logging and options passing I wanted to add the corresponding members to the template whithout having to write initializers for every derived static class.
Please note that the following code is not actually working, because there is some SDK involved.
I'm just aksing for the right approach, not right code.
Thanks in advance. :)
template.h:
#ifndef _TEMPLATE_H
#define _TEMPLATE_H
#include "stats.h"
template<class T>
class TemplateObj
{
public:
static void SetParameters(const Options& options)
{
T::_options = options; // Is this even possible?
T::Init();
T::DoStuff(_options);
}
protected:
static void Message() { stats.Print("Message from Template static method"); }
static Stats& TemplateObj<T>::stats = Stats::GetInstance(); // This will not work as this is a non-trivial initializer, how to do it correctly? Stats::GetInstance() retrieves a singleton instance
static Options& TemplateObj<T>::_options; // Possible?
};
#endif
derived.h:
#ifndef _DERIVED_H
#define _DERIVED_H
#include "template.h"
class Derived :TemplateObj < Derived >
{
public:
static void Init();
static void DoStuff(Options& options)
};
#endif
derived.cpp:
#include "derived.h"
void Derived::Init()
{
// Init stuff here
TemplateObj::Message(); // Call static method from template directly
}
void Derived::DoStuff(Options& options)
{
// Do something with options
stats.Print("Message from derived static method."); // Access to "stats" here. "stats" should be declared and initialized inside the template.
options.Load(); // Example
}
main.h
#include "derived.h"
main()
{
TemplateObj<Derived>::SetParameters(new Options);
}
Basically, you don't need to put TemplateObj<T>:: before the function definition if it is inside the class definition. The following two are both valid:
template<class T>
class A{
void func( void );
};
template<class T>
void A<T>::func() { /* Okay */ }
template<class T>
class B {
void func( void ){ /* Okay */ }
};
In your case, replace the following static Stats& TemplateObj<T>::stats = Stats::GetInstance(); with static Stats& stat() { return Stats::GetInstance(); }
And the following static Options& TemplateObj<T>::_options; with this static Options& _options;.
On the other hand, replace this T::_options = options; with TemplateObj<T>::_options = options;.
Why does following code raise an exception (in createObjects call to map::at)
alternativly the code (and its output) can be viewed here
intererestingly the code works as expected if the commented lines are uncommented with both microsoft and gcc compiler (see here), this even works with initMap as ordinary static variable instead of static getter.
The only reason for this i can think of is that the order of initialization of the static registerHelper_ object (factory_helper_)and the std::map object (initMap) are wrong, however i cant see how that could happen, because the map object is constructed on first usage and thats in factory_helper_ constructor, so everything should be alright shouldnt it ?
I am even more suprised that those doNothing() lines fix the issue, because that call to doNothing() would happen after the critical section (which currently fails) is passed anyway.
EDIT: debugging showed, that without the call to factory_helper_.doNothing(), the constructor of factory_helper_ is never called.
#include <iostream>
#include <string>
#include <map>
#define FACTORY_CLASS(classtype) \
extern const char classtype##_name_[] = #classtype; \
class classtype : FactoryBase<classtype,classtype##_name_>
namespace detail_
{
class registerHelperBase
{
public:
registerHelperBase(){}
protected:
static std::map<std::string, void * (*)(void)>& getInitMap() {
static std::map<std::string, void * (*)(void)>* initMap = 0;
if(!initMap)
initMap= new std::map<std::string, void * (*)(void)>();
return *initMap;
}
};
template<class TParent, const char* ClassName>
class registerHelper_ : registerHelperBase {
static registerHelper_ help_;
public:
//void doNothing(){}
registerHelper_(){
getInitMap()[std::string(ClassName)]=&TParent::factory_init_;
}
};
template<class TParent, const char* ClassName>
registerHelper_<TParent,ClassName> registerHelper_<TParent,ClassName>::help_;
}
class Factory : detail_::registerHelperBase
{
private:
Factory();
public:
static void* createObject(const std::string& objclassname) {
return getInitMap().at(objclassname)();
}
};
template <class TClass, const char* ClassName>
class FactoryBase {
private:
static detail_::registerHelper_<FactoryBase<TClass,ClassName>,ClassName> factory_helper_;
static void* factory_init_(){ return new TClass();}
public:
friend class detail_::registerHelper_<FactoryBase<TClass,ClassName>,ClassName>;
FactoryBase(){
//factory_helper_.doNothing();
}
virtual ~FactoryBase(){};
};
template <class TClass, const char* ClassName>
detail_::registerHelper_<FactoryBase<TClass,ClassName>,ClassName> FactoryBase<TClass,ClassName>::factory_helper_;
FACTORY_CLASS(Test) {
public:
Test(){}
};
int main(int argc, char** argv) {
try {
Test* test = (Test*) Factory::createObject("Test");
}
catch(const std::exception& ex) {
std::cerr << "caught std::exception: "<< ex.what() << std::endl;
}
#ifdef _MSC_VER
system("pause");
#endif
return 0;
}
The problem is not related to initialization order, but rather to template instantiation.
Templated code is instantiated on demand, that is, the compiler will not instantiate any templated code that is not used in your program. In particular, in your case the static class member FactoryBase<>::factory_helper_ is not being instantiated and thus it does not exist in the final binary, it does not register itself... (you can check this with 'nm' from the gnu toolchain, that will show the list of symbols present in your executable)
Try changing the FactoryBase constructor to this:
template <class TClass, const char* ClassName>
class FactoryBase {
//...
FactoryBase(){
factory_helper_;
}
//...
};
This will force the compiler into actually instantiating the static member in the binary and you should be set. There is no need to create an empty method and calling it.
EDIT: As an answer to the comment, towards the end of paragraph ยง14.7.1[temp.inst]/1 in the current standard:
Unless a member of a class template or
a member template has been explicitly
instantiated or explicitly
specialized, the specialization of the
member is implicitly instantiated when
the specialization is referenced in a
context that requires the member
definition to exist; in particular,
the initialization (and any associated
side-effects) of a static data member
does not occur unless the static data
member is itself used in a way that
requires the definition of the static
data member to exist.
#define FACTORY_CLASS(classtype) \
class classtype; \
extern const char classtype##_name_[] = #classtype; \
template detail_::registerHelper_<FactoryBase<classtype,classtype##_name_>,classtype##_name_> FactoryBase<classtype,classtype##_name_>::factory_helper_; \
class classtype : FactoryBase<classtype,classtype##_name_>
explicitly instantiating factory_helper_ fixed the issue.
Is it possible to use member function pointers with template meta-programming? Such as:
class Connection{
public:
string getName() const;
string getAlias() const;
//more stuff
};
typedef string (Connection::*Con_Func)() const;
template<Con_Func _Name>
class Foo{
Connection m_Connect;
public:
Foo(){
cout << (m_Connect.*_Name)();
}
};
typedef Foo<&Connection::getName> NamedFoo;
typedef Foo<&Connection::getAlias> AliasFoo;
Granted, this is rather contrived but is it possible? (yes, there are probably much better ways but humor me.)
Check out this discussion on the subject of pointers-to-nonstatic-members as template parameters. It looks like there are issues with the VC++ implementation.
If you are asking, can pointers to members be used as template parameters, then yes they can. There are a number of errors in your code though. This is, I think, what you might mean:
// Necessary includes
#include <string>
#include <iostream>
#include <ostream>
class Connection{
public:
// Use std:: for standard string class
std::string getName() const;
std::string getAlias() const;
//more stuff
};
typedef std::string (Connection::*Con_Func)() const;
template<Con_Func _Name>
class Foo{
Connection m_Connect;
public:
// Constructors don't have return values
Foo(){
// Correct syntax for function call through pointer to member
std::cout << (m_Connect.*_Name)();
}
};
typedef Foo<&Connection::getName> NamedFoo;
typedef Foo<&Connection::getAlias> AliasFoo;