Suppose you have to write a template library that operates on a client-supplied type. Also, suppose that this library really needs to access a global variable parameterized by the client-supplied type. How would you go about implementing this pattern?
#AnonymousCoward
this is derived from your solution. note the initialization/destruction patterns in this variant (read the output if you don't have it memorized already). you can use this to defer creation until access, and to destruct and free at termination (which may be useful for custom types):
#include <iostream>
#include <memory>
class t_custom {
public:
t_custom() {
std::cout << "custom ctor: " << __PRETTY_FUNCTION__ << "\n";
}
~t_custom() {
std::cout << "custom dtor: " << __PRETTY_FUNCTION__ << "\n";
}
};
template<typename T>
class Global {
public:
static T* Shared() {
std::cout << "enter: " << __PRETTY_FUNCTION__ << "\n";
static std::auto_ptr<T>pVar(new T);
std::cout << "access: " << __PRETTY_FUNCTION__ << ":\t\t";
return pVar.get();
}
private:
Global();
~Global();
Global(const Global& rhs);
Global& operator=(const Global& rhs);
};
template<typename T>
class Global_orig {
public:
static T* const pVar;
private:
Global_orig();
Global_orig(const Global_orig& rhs);
Global_orig& operator=(const Global_orig& rhs);
};
template<typename T>T* const Global_orig<T>::pVar(new T); // << oh no! global construction
int main(int argc, char* const argv[]) {
std::cout << ">> main: " << __PRETTY_FUNCTION__ << "\n\n";
std::cout << Global<float>::Shared() << "\n";
std::cout << Global<int>::Shared() << "\n";
std::cout << Global<t_custom>::Shared() << "\n";
std::cout << Global_orig<t_custom>::pVar << "\n";
std::cout << "\n<< main: " << __PRETTY_FUNCTION__ << "\n\n";
return 0;
}
it may also be a good idea for the client to supply a factory functor for you, rather than forcing them to use T's default initializer.
Here is the solution I use to emulate this behavior:
template <typename T> class Global {
public:
static T *pVar;
private:
Global() {}
Global(const Global& rhs) {}
void operator=(const Global& rhs) {}
};
template <typename T> T* Global<T>::pVar = new T;
It seems to do what I want for my particular application. Is there any problem that restricts its applicability?
Related
I'm experimenting with a class which is a wrapper of multiple modules. Each module needs some configuration. I try to solve this with a variadic template functions to ensure at compiletime, that each module which should be generated has it's configuration data given.
The only problem left is that the template argument deduction/substitution is failing for my creation function template. If the whole wrapper would be a templated class it would work.
Following I'm providing a little example of the problem. I tried to keep it as simple as possible.
class ClassA{};
class ClassB{};
template<class Module>
class FactoryModuleConfig;
template<>
class FactoryModuleConfig<ClassA>{
public:
FactoryModuleConfig(){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
virtual ~FactoryModuleConfig(){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
template<>
class FactoryModuleConfig<ClassB>{
public:
FactoryModuleConfig(){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
virtual ~FactoryModuleConfig(){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
template< class... Args >
class FactoryConfig;
template<class Arg, class... Args>
class FactoryConfig<Arg, Args...> : public FactoryModuleConfig<Arg>, public virtual FactoryConfig<Args...>
{
public:
FactoryConfig(){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
virtual ~FactoryConfig( ){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
template<>
class FactoryConfig<>
{
public:
FactoryConfig(){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
virtual ~FactoryConfig( ){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
class myFactoryConfig : public FactoryConfig<ClassA,ClassB>{
public:
myFactoryConfig(){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
virtual ~myFactoryConfig( ){ std::cout << __PRETTY_FUNCTION__ << std::endl; }
int getNumberOfModules() const { return 1; }
};
class Factory{
Factory(){}
public:
virtual ~Factory(){}
template<class ...Args>
static Factory* create(FactoryConfig<Args...>* pCfg){ return new Factory();}
};
template<class ...Args>
class Factory2{
public:
Factory2(FactoryConfig<Args...>* pCfg){}
virtual ~Factory2(){}
};
int main()
{
// Solution 1
myFactoryConfig* pCfg = new myFactoryConfig(); // <-- why is this not working
// FactoryConfig<ClassA,ClassB>* pCfg = new myFactoryConfig(); // <-- and this works like a charm
Factory* pfac = Factory::create<ClassA,ClassB>(pCfg);
// Solution 2 // Solution 2 is always working
//FactoryConfig<ClassA,ClassB>* pCfg = new myFactoryConfig();
//Factory2<ClassA,ClassB>* pfac = new Factory2<ClassA,ClassB>(pCfg);
delete pfac;
delete pCfg;
return 0;
}
Here is the example at coliru: https://coliru.stacked-crooked.com/a/744c58c7025c1c2f
I'm starting to doubt my c++ knowledge...
Solution without explanation as the previous one was incorrect, stil digging...
You can solve this by making FactoryConfig only inherits FactoryModule<>:
template< class... Args >
class FactoryConfig: public FactoryModuleConfig<Args>...
{
public:
FactoryConfig() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
virtual ~FactoryConfig() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
Compiles fine under clang, possibly a bug in gcc? See g++ c++17 class template argument deduction not working in a very specific case for a vaguely similar example.
I tried to build a very simple version of std::function. Below the code of a very first version. My question is about the lifetime of the temporary object from the lambda-expression, because I'm actually storing a reference to it. Or is the lifetime of the object prolonged?
It tried to use a copy of the function (T mf instead of const T& mf inside struct F), but that gives an error due to the decaying of the function to a pointer.
#include <iostream>
template<typename T>
struct F {
F(const T& f) : mf{f} {
std::cout << __PRETTY_FUNCTION__ << '\n';
}
void test() {
std::cout << __PRETTY_FUNCTION__ << '\n';
mf();
}
const T& mf;
};
template<typename T>
struct F<T*> {
F(T f) : mf{f} {
std::cout << __PRETTY_FUNCTION__ << '\n';
}
void test() {
std::cout << __PRETTY_FUNCTION__ << '\n';
mf();
}
T* mf;
};
void g() {
std::cout << __PRETTY_FUNCTION__ << '\n';
}
int main() {
F<void(void)> f1(g);
f1.test();
auto g1 = g;
F f2(g1);
f2.test();
F f3([](){ // lifetime?
std::cout << __PRETTY_FUNCTION__ << '\n';
});
f3.test();
auto l1 = [](){
std::cout << __PRETTY_FUNCTION__ << '\n';
};
F f4(l1);
f4.test();
}
You do have lifetime problems here: lifetime extension thanks to const only applies for local const references.
You need to make sure that the referenced function lives at least as long as the wrapper, or you need to copy/move the function into the wrapper.
but that gives an error due to the decaying of the function to a pointer
You can use std::decay_t<T> to ensure that you're copying/moving objects (e.g. closures) into the wrapper.
Using a std::shared_ptr expresses shared ownership and optionality (with its possibility to be null).
I find myself in situations where I want to express shared ownership only in my code, and no optionality. When using a shared_ptr as a function parameter I have to let the function check that it is not null to be consistent/safe.
Passing a reference instead of course is an option in many cases, but I sometimes would also like to transfer the ownership, as it is possible with a shared_ptr.
Is there a class to replace shared_ptr without the possibility to be null, some convention to handle this problem, or does my question not make much sense?
You are asking for not_null wrapper class. Fortunately your issue is already addressed by C++ experts guideline and there are already example implementations - like this one. Search for not_null class template.
You could write a wrapper around std::shared_ptr that only allows creation from non-null:
#include <memory>
#include <cassert>
template <typename T>
class shared_reference
{
std::shared_ptr<T> m_ptr;
shared_reference(T* value) :m_ptr(value) { assert(value != nullptr); }
public:
shared_reference(const shared_reference&) = default;
shared_reference(shared_reference&&) = default;
~shared_reference() = default;
T* operator->() { return m_ptr.get(); }
const T* operator->() const { return m_ptr.get(); }
T& operator*() { return *m_ptr.get(); }
const T& operator*() const { return *m_ptr.get(); }
template <typename XT, typename...XTypes>
friend shared_reference<XT> make_shared_reference(XTypes&&...args);
};
template <typename T, typename...Types>
shared_reference<T> make_shared_reference(Types&&...args)
{
return shared_reference<T>(new T(std::forward<Types>(args)...));
}
Please note that operator= is missing yet. You should definitely add it.
You can use it like this:
#include <iostream>
using std::cout;
using std::endl;
struct test
{
int m_x;
test(int x) :m_x(x) { cout << "test("<<m_x<<")" << endl; }
test(const test& t) :m_x(t.m_x) { cout << "test(const test& " << m_x << ")" << endl; }
test(test&& t) :m_x(std::move(t.m_x)) { cout << "test(test&& " << m_x << ")" << endl; }
test& operator=(int x) { m_x = x; cout << "test::operator=(" << m_x << ")" << endl; return *this;}
test& operator=(const test& t) { m_x = t.m_x; cout << "test::operator=(const test& " << m_x << ")" << endl; return *this;}
test& operator=(test&& t) { m_x = std::move(t.m_x); cout << "test::operator=(test&& " << m_x << ")" << endl; return *this;}
~test() { cout << "~test(" << m_x << ")" << endl; }
};
#include <string>
int main() {
{
auto ref = make_shared_reference<test>(1);
auto ref2 = ref;
*ref2 = test(5);
}
{
test o(2);
auto ref = make_shared_reference<test>(std::move(o));
}
//Invalid case
//{
// test& a = *(test*)nullptr;
// auto ref = make_shared_reference<test>(a);
//}
}
Output:
test(1)
test(5)
test::operator=(test&& 5)
~test(5)
~test(5)
test(2)
test(test&& 2)
~test(2)
~test(2)
Example on Coliru
I hope I didn't forget anything that might result in undefined behaviour.
After taking a look at GSL's not_null class, which calls std::terminate() instead of abort();
Here is how I achieved it:
template <typename T>
class NonNull : public std::shared_ptr<T> {
typedef std::shared_ptr<T> super;
public:
inline NonNull()
: super(new T())
{
if ( ! super::get()) {
abort(); // Out of memory.
}
}
inline explicit NonNull(T *ptr)
: super(ptr)
{
if ( ! super::get()) {
abort(); // Input was null.
}
}
}
Basically, forces us to construct the class of T type.
Usage:
// Directly is a `std::shared_ptr` type:
NonNull<MyClass> myVariable;
// Unlike:
gsl::not_null<std::shared_ptr<MyClass > > myVariable;
I just made a wrapper for move and copy operations to inject into code to see which is called in case of default implementations. I'm getting close to understanding when what is called but would like to double check at times.
I'm not sure if method 1 of using T::T; is better for the constructors than method 2 of forwarding the arguments like unique_ptr? I found it in this thread Forwarding all constructors in C++0x
In move constructor and assignment I use std::move to pass onto the super class. Should this be std::forward and if so, how? I get errors trying to use it.
#ifndef MOVECOPY_OBSERVER_H
#define MOVECOPY_OBSERVER_H
#include <iostream>
template<class T>
class MoveCopyObserver : public T {
public:
//1: Use "using" for constructors
//From https://stackoverflow.com/questions/3119929/forwarding-all-constructors-in-c0x
using T::T;
//2: Forward all args, unique_ptr style.
/*
template<typename... Args>
MoveCopyObserver(Args&&... args)
: T(std::forward<Args>(args)...)
{
};*/
// *************************************************************************
virtual ~MoveCopyObserver() = default;
// *************************************************************************
MoveCopyObserver(const MoveCopyObserver& other)
: T(other)
{
std::cout << "Copy constructor " << typeid(T).name() << std::endl;
}
// *************************************************************************
MoveCopyObserver(MoveCopyObserver && other)
: T(std::move(other)) //3: std::forward instead?
{
std::cout << "Move constructor " << typeid(T).name() << std::endl;
}
// *************************************************************************
MoveCopyObserver& operator=(const MoveCopyObserver& other)
{
T::operator=(other);
std::cout << "Copy assignment " << typeid(T).name() << std::endl;
return *this;
}
// *************************************************************************
MoveCopyObserver& operator=(MoveCopyObserver&& other)
{
T::operator=(std::move(other)); //3: std::forward instead?
std::cout << "Move assignment " << typeid(T).name() << std::endl;
return *this;
}
};
#endif //MOVECOPY_OBSERVER_H
The usage would be on the stack or through smart pointers, like so:
class A {
public:
A(std::string ss)
{
s = ss;
}
void f()
{
std::cout << "\"" << s << "\"" << std::endl;
}
private:
std::string s;
};
A a("Test instance");
a.foo();
MoveCopyObserver<A> b("Another instance");
b.foo();
from the code below, I get the following output:
Call member_function
Derived member function
Call template_function
template function
Derived member function
As expected, the specialization of template_function is not called here because derived is of type Base*, but the correct version of member_function is called.
However, sometimes, it may be useful to call not-member functions in template functions.
Does exist a way to ensure that the specialized version of the template function will be called when dynamic instances of Derived class are declared as being of type Base*?
Thanks!
#include <iostream>
// Base and Derived classes
class Base
{
public:
virtual void member_function() const
{ std::cout << "Base member function" << std::endl; };
};
class Derived : public Base
{
public:
virtual void member_function() const
{ std::cout << "Derived member function" << std::endl;};
};
// Functions
template<typename T>
void template_function(T const & arg)
{
std::cout << "template function" << std::endl;
arg.member_function();
}
template<>
void template_function(Derived const & arg)
{
std::cout << "Specialized function" << std::endl;
arg.member_function();
}
// Main
int main ()
{
Base * derived = new Derived();;
std::cout << "Call member_function" << std::endl;
derived->member_function();
std::cout << std::endl;
std::cout << "Call template_function" << std::endl;
template_function(*derived);
}
You can add two templates template_function that you enable_if on std::base_of<T, Derived>, like this
// Functions
template<typename T, std::enable_if_t<not std::is_base_of<T, Derived>::value>* = nullptr>
void template_function(T const & arg)
{
std::cout << "template function" << std::endl;
arg.member_function();
}
template<typename T, std::enable_if_t<std::is_base_of<T, Derived>::value>* = nullptr>
void template_function(T const & arg)
{
std::cout << "Specialized function" << std::endl;
arg.member_function();
}
// Main
int main ()
{
Base const * base = new Base();
Base const * derived = new Derived();
std::cout << "Call member_function" << std::endl;
base->member_function();
derived->member_function();
std::cout << std::endl;
std::cout << "Call template_function" << std::endl;
template_function(*base);
template_function(*derived);
}
Live Example.
Alternatively, and much simpler, you can simply add a template_function(Base const&) overload
// Functions
template<typename T>
void template_function(T const & arg)
{
std::cout << "template function" << std::endl;
arg.member_function();
}
void template_function(Base const & arg)
{
std::cout << "Specialized function" << std::endl;
arg.member_function();
}
Live Example