Why is template argument deduction/substitution failing for function templates only? - c++

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.

Related

Child class' dynamic method calls parent class' virtual method when used in lambda capture / results in segmentatin fault

Edit: with final keyword on the implementations of the virtual function results in printing the correct string, but why is the final keyword here needed? Could somebody explain?
I am tinkering with variadic templates, I have pretty generic classes D1, D2, D3, ... and they all derive from a class A. Each class has a static and a dynamic print functions, the parent class has a virtual dynamic print function for dynamic dispatching. When I try to reproduce it on a single file:
class A {
public:
virtual void printDynamic();
static void printStatic();
}
class D1 : public A {
public:
virtual void printDynamic();
static void printStatic();
}
And I have following variants:
std::variant<A,As...> apvar;
std::variant<A*,As*...> avar;
I instantiate both variants with all the derived classes D1,D2,... (I know upcasting Pointers i just want to dereference to their types and do random stuff)
I have implemented recursive visitors for the wrappers, i need to capture this because I encapsulated most of the functions in a class, when I call the visitor on classes I get the names "DX", "DX" ; X corresponding to 1.
template<class X, class Y, class... Zs>
void visit_actor(){
std::visit(
[this](auto&& value){
if constexpr(std::is_same<expr_type<decltype(value)>,expr_type<X>>::value){
value.printStaticName();
value.printDynamicName();
} else{
visit_actor<Y,Zs...>();
}
}, avar
);
}
But if I call the visitor on pointer variants and when I call the functions:
For the static function I get: "DX" with X corresponding to I, but when I call the dynamic function I get the name: "Abstract A".
template<class X, class Y, class... Zs>
void visit_pointer(){
std::visit(
[this](auto&& value){
if constexpr(std::is_same<expr_type<decltype(value)>,expr_type<X>>::value){
value->printStaticName();
value->printDynamicName();
} else{
visit_pointer<Y,Zs...>();
}
}, apvar
);
}
I have tried reading about it in c++ documentation but could not find the reason yet. What could be the reason that the static function of the derived class is called but the parents virtual function is called ?
For A Minimal Producable example, you need to instantiate the classes:
#include <variant>
#include <iostream>
#include <string>
template <class T>
using expr_type = std::remove_cv_t<std::remove_reference_t<T>>;
template<class A,class... As>
class ActorWrapper{
public:
std::variant<A,As...> var;
template<class Ins>
ActorWrapper(Ins ins) : var(ins) {}
};
template<class A,class... As>
class ActorPointer{
public:
std::variant<A,As... > var;
template<class T>
ActorPointer(T* t) : var(t) {}
};
class X {
public:
int a;
virtual std::string getDynamicName() {
return "dynamic X";
}
static std::string getStaticName(){
return "static X";
}
};
class D1 : public X{
public:
bool b;
std::string getDynamicName() override {
return "dynamic D1";
}
static std::string getStaticName(){
return "static D1";
}
};
class D2: public X {
public:
bool b;
std::string getDynamicName() override {
return "dynamic D2";
}
static std::string getStaticName(){
return "static D2";
}
};
template<class A, class... As>
class TemplatedAGraph{
private:
//change aw to correspond to ap
template<class X>
void visit_actor(){
std::visit(
[this](auto&& value){
if constexpr(std::is_same<expr_type<decltype(value)>, expr_type<X>>::value){
std::cout << "z" << std::endl;
std::cout << value.getStaticName() << std::endl;
std::cout << value.getDynamicName() << std::endl;
}else{
std::cout << "d" << std::endl;
return;
}
}, aw.var
);
}
template<class X, class Y, class... Zs>
void visit_actor(){
std::visit(
[this](auto&& value){
if constexpr(std::is_same<expr_type<decltype(value)>, expr_type<X>>::value){
std::cout << "x" << std::endl;
std::cout << value.getStaticName() << std::endl;
//std::cout << value.getDynamicName() << std::endl;
} else{
std::cout << "y" << std::endl;
visit_actor<Y,Zs...>();
}
}, aw.var
);
}
template<class X>
void visit_pointer(){
std::visit(
[this](auto&& value){
if constexpr(std::is_same<expr_type<decltype(value)>, expr_type<X>>::value){
std::cout << "a" << std::endl;
std::cout << value->getStaticName() << std::endl;
std::cout << value->getDynamicName() << std::endl;
}else{
std::cout << "b" << std::endl;
return;
}
}, ap.var
);
}
template<class X, class Y, class... Zs>
void visit_pointer(){
std::visit(
[this](auto&& value){
if constexpr(std::is_same<expr_type<decltype(value)>, expr_type<X>>::value){
std::cout << "c" << std::endl;
std::cout << value->getStaticName() << std::endl;
std::cout << value->getDynamicName() <<std::endl;
} else{
//std::cout << typeid(decltype(value)).name() <<std::endl;
//std::cout << typeid(X).name() <<std::endl;
//std::cout << std::is_same_v<decltype(value),X> << std::endl;
std::cout << "d" << std::endl;
visit_pointer<Y,Zs...>();
}
}, ap.var
);
}
public:
ActorPointer<A*,As*...> ap;
ActorWrapper<A,As...> aw;
void print_names(){
visit_actor<A,As...>();
}
void print_names_w_pointer(){
visit_pointer<A*,As*...>();
}
//change ap to coresspond to aw
template<class X>
TemplatedAGraph(X a) : ap(&a), aw(a) {}
};
int main(){
D2 d2;
D2* d2ref = &d2;
std::cout << d2ref->getDynamicName() << std::endl;
TemplatedAGraph<D1,D2> tag(d2);
tag.print_names();
tag.print_names_w_pointer();
}
The Output is:
thrud#thrud ~/wörk/test $ g++ main.cpp -std=c++17
thrud#thrud ~/wörk/test $ ./a.out
dynamic D2
y
z
static D2
dynamic D2
d
a
static D2
Segmentation fault
So I think I have stumbled upon an undefined behaviour, but still I would like to know the reason.
TemplatedAGraph(X a) : ap(&a), aw(a) {} stores a pointer to a local variable in ap. That pointer becomes dangling soon afterwards. Any attempt to access it then exhibits undefined behavior.
You might have meant TemplatedAGraph(X& a) :.... This way, your code works, as far as I can tell.

Using template specialization to compare pointer references

Based on this SO answer, I was experimenting with something similar but with a pointer:
#include <iostream>
class Bar {
public:
virtual ~Bar() {}
};
class Foo: Bar {
public:
Foo() { std::cout << "Foo::Foo()" << std::endl; }
~Foo() override { std::cout << "Foo::~Foo()" << std::endl; }
};
class Faz {
public:
Faz() { std::cout << "Faz::Faz()" << std::endl; }
~Faz() { std::cout << "Faz::~Faz()" << std::endl; }
};
template <typename T>
typename std::enable_if<std::is_base_of<Bar, std::remove_pointer<T>>::value>::type
func(char const* type, T) {
std::cout << type << " is derived from Bar" << std::endl;
}
template <typename T>
typename std::enable_if<!std::is_base_of<Bar, std::remove_pointer<T>>::value>::type
func(char const* type, T) {
std::cout << type << " is NOT derived from Bar" << std::endl;
}
int main()
{
func("std::unique_ptr<Foo>", std::unique_ptr<Foo>());
func("std::unique_ptr<Faz>", std::unique_ptr<Faz>());
}
cout is :
std::unique_ptr<Foo> is NOT derived from Bar
std::unique_ptr<Faz> is NOT derived from Bar
Why does !std::is_base_of<Bar, type_identity<std::remove_pointer<T>>>::value always evaluate as true? I assumed (as a beginner):
std::unique_ptr<Foo> is derived from Bar
std::unique_ptr<Faz> is NOT derived from Bar
I'm probably missing something stupid.
std::remove_pointer<> acts on raw pointer types.
The smart pointer's type is not related to the class hierarchy of referent type

Switching between specialization and overloading

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

How to specialize a static function of a class template?

When I tried to write something like this:
#include <iostream>
template <class T>
class A
{
public:
static void doit();
};
template <>
static void A<int>::doit()
{
std::cout << "int" << std::endl;
}
template <>
static void A<double>::doit()
{
std::cout << "double" << std::endl;
}
int main()
{
A<int>::doit();
A<double>::doit();
}
I got a compile error:
Specializing the whole class is ok. I just want to know is there any way to specialize only the static function?
You should specify static keyword only once, in declaration.
Try this:
template<>
void A<int>::doit()
{
std::cout << "int" << std::endl;
}
template<>
void A<double>::doit()
{
std::cout << "double" << std::endl;
}

How to define a global variable template in C++?

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?