I'm trying to write a generic factory class with automatic self-registration of types for my application.
In order to allow flexibility, this factory has a variadic template parameter for constructor arguments; i.e. it allows either default constructors or constructors requiring any number of arguments. The parameter names are fairly self-explanatory; the AbstractType is the abstract base class for the factory; the returned object will be a std::shared_ptr of this type.
This generic factory works fine and all of the tests I wrote for it were working perfectly fine, until I tried to create a factory for a specific class hierarchy containing classes (as data members) that do not permit copy construction or assignment. I tried to fix this by using an rvalue reference for the template argument; however, this does not work in the manner that I expected. Specifically, if I define the factory instance to take a constructor parameter of type A&&, this fails with an error telling me that there is no conversion from A to A&&.
In this sample, My_Abstract, Data_Context, and Other_Class are declared elsewhere. As described briefly above, the idea here is that a concrete type CT will have a constructor with the signature:
class CT {
CT(Data_Context&&, Other_Class const&);
/* ... */
};
class My_Abstract; // forward declaration
template <class ConcreteType>
using My_Factory_Registrar =
Factory_Registrar<ConcreteType, My_Abstract, Data_Context &&, Other_Class const&>;
using My_Factory =
Generic_Factory<My_Abstract, Data_Context &&, Other_Class const&>;
Perhaps I am missing something fundamental here, but when I revise the code to be:
template <class ConcreteType>
using My_Factory_Registrar =
Factory_Registrar<ConcreteType, My_Abstract, Data_Context const&, Other_Class const&>;
using My_Factory =
Generic_Factory<ConcreteType, Data_Context const&, Other_Class const&>;
Then everything compiles and works correctly. I am well aware that an r-value can be used for a const reference parameter, so I am not confused as to why this worked, as much as I am completely confused why the first code snippet did not work. It almost appears like the rvalue reference qualifier was removed in the process of variadic template expansion.
I'm not sure whether or not it will help at all in clarifying thing, but the code for the factory class itself is as follows:
template <class AbstractType, class...ConstructorArgs>
class Generic_Factory{
public:
static std::shared_ptr<AbstractType> Construct(std::string key, ConstructorArgs... arguments){
auto it = Get_Registry()->find(key);
if (it == Get_Registry()->cend())
return nullptr;
auto constructor = it->second;
return constructor(arguments...);
}
using Constructor_t = std::function<std::shared_ptr<AbstractType>(ConstructorArgs...)>;
using Registry_t = std::map< std::string, Constructor_t>;
Generic_Factory(Generic_Factory const&) = delete;
Generic_Factory& operator=(Generic_Factory const&) = delete;
protected:
Generic_Factory(){}
static Registry_t* Get_Registry();
private:
static Registry_t* _registry_;
};
template <class ConcreteType, class AbstractType, class...ConstructorArgs>
struct Factory_Registrar : private Generic_Factory<AbstractType, ConstructorArgs...>{
using Factory = Generic_Factory<AbstractType, ConstructorArgs...>;
using Constructor_t = typename Factory::Constructor_t;
public:
Factory_Registrar(std::string const& designator, Constructor_t object_constructor){
auto registry = Factory::Get_Registry();
if (registry->find(designator) == registry->cend())
registry->insert(std::make_pair(designator, object_constructor));
}
};
Thanks for your help.
Shmuel
Perfect Forwarding is intended to be used in these cases. Your code is quite long. I use a simplified version of make_unique for demonstration.
template <typename T, typename ...Args>
auto make_unique(Args&&... args) -> std::unique_ptr<T>
{
return std::unique_ptr<T>{new T(std::forward<Args>(args)...)};
}
To be able to forward rvalue input arguments without losing type information, you need to use universal references. The prototypical example is :
template<class T>
void Forwarder(T&& t)
{
Func(std::forward<T>(t));
}
This way, there is no loss of type information and the right overload of Func gets called.
On the other hand, if the body of Forwarder called Func(t), only the lvalue overload of Func would match.
Related
I'm writing a Factory for producing instances of subclasses of a base class using their name, and using this (templated) factory with my class Foo. Never mind the entire code, but essentially, the factory has a map from string to functions creating instances; and a template parameter controls which arguments these functions take. In my case, the ctor of Foo, and any subclass of foo, takes a const Bar&, and that's what the variadic template for ctor arguments consist of.
I have:
template<typename SubclassKey, typename T, typename... ConstructionArgs>
class Factory {
public:
using Instantiator = T* (*)(ConstructionArgs&&...);
private:
template<typename U>
static T* createInstance(ConstructionArgs&&... args)
{
return new U(std::forward<ConstructionArgs>(args)...);
}
using Instantiators = std::unordered_map<SubclassKey,Instantiator>;
Instantiators subclassInstantiators;
public:
template<typename U>
void registerSubclass(const SubclassKey& subclass_id)
{
static_assert(std::is_base_of<T, U>::value,
"This factory cannot register a class which is is not actually "
"derived from the factory's associated class");
auto it = subclassInstantiators.find(subclass_id);
if (it != subclassInstantiators.end()) {
throw std::logic_error("Repeat registration of the same subclass in this factory.");
}
subclassInstantiators.emplace(subclass_id, &createInstance<U>);
}
};
And by popular demand, here's also...
class Foo {
using FooFactory = Factory<std::string, Foo, const Bar&>;
private:
static FooFactory& getTestFactory() {
static FooFactory kernel_test_factory;
return kernel_test_factory;
}
//...
public:
//...
template <typename U>
static void registerInFactory(const std::string& name_of_u) {
Foo::getTestFactory().registerSubclass<U>(name_of_u);
}
Bar bar;
Foo(const Bar& bar_) : bar(bar_) { };
virtual ~Foo() {}
// ...
};
class NiceFoo : public Foo {
// no ctors and dtors
};
Unfortunately, for some reason, when I call
I get a complaint about the ctor expecting a const Bar& while the argument list I supposedly provide in my createInstance is actually a const Bar.
Questions:
Why is the reference "disappearing"?
Am I doing something wrong? Should I be approaching this matter differently?
GCC error output:
/home/joeuser/myproj/../util/Factory.h(36): error: no instance of constructor "NiceFoo::NiceFoo" matches the argument list
argument types are: (const Bar)
detected during:
instantiation of "T *util::Factory<SubclassKey, T, ConstructionArgs...>::createInstance<U>(ConstructionArgs &&...) [with SubclassKey=std::string, T=Foo, ConstructionArgs=<const Bar &>, U=NiceFoo]"
(59): here
instantiation of "void util::Factory<SubclassKey, T, ConstructionArgs...>::registerSubclass<U>(const SubclassKey &) [with SubclassKey=std::string, T=Foo, ConstructionArgs=<const Bar &>, U=NiceFoo]"
/home/joeuser/myproj/../Foo.h(79): here
instantiation of "void Foo::registerInFactory<U>(const std::string &) [with U=NiceFoo]"
/home/joeuser/myproj/NiceFoo.cpp(122): here
There are two problems in your code: the immediate one, and a fundamental one.
The immediate one is that NiceFoo does not declare any constructors. You claimed that "it inherits Foo's constructors," but that's not the case in the code you've shown. Inheriting constructors would be achieved by this:
class NiceFoo : public Foo {
public:
using Foo::Foo;
}
Without the using declaration, you just have a class with no constructors declared (it will have the copy, move, and parameterless ones generated by default, but no new ones).
There is also a fundamental issue in your design: You're trying to use template parameters of a class template in perfect forwarding. That doesn't work; perfect forwarding relies on template argument deduction, which only happens with function templates.
In other words, this: ConstructionArgs&&... does not create forwarding references, but plain old rvalue references. In the concrete case you've presented, it does not really matter, because ConstructionArgs is const Bar & and reference collapsing makes it work out. But if you had included a value type (and not reference type) among the constructor arguments, createInstance would have been using plain rvalue references and initialisation from an lvalue would have been impossible.
The correct solution to this would be to have ConstructionArgs mirror exactly what the constructor of T expects—in other words, drop the && from use of ConstructionArgs everywhere, and use std::move instead of std::forward inside createInstance. One second thought, the std::forward should be able to stay and do the right thing; basically equivalent to a no-op for lvalue references, and to a std::move for values and rvalue references.
I'm writing a simple universal pool. The template class takes a parameter in the constructor that is a factory function to instantiate objects in the pool as needed.
template<typename T>
struct Foo {
std::function <T*()> factory_;
Foo(std::function<T*()> factory): factory_(factory) {}
};
This compiles fine, but I wanted to make a default argument for the constructor using lambda:
Foo(std::function<T*()> factory = [](){return new T();} ): factory_(factory) {}
This does not compile - it says that T is unknown. Is there a way to make lambda expressions aware of class template parameters? I tried using typedef, but to no avail.
This should work as proposed, however you might have hit a bug in VC++ (it's not exactly C++11 ready yet).
As a workaround, you might try to replace your lambda by a private static method instead.
template <typename T>
class LIFOPool
{
std::function <T*()> factory_;
//...details irrelevant
static T* DefaultMake() { return new T{}; }
public:
LIFOPool(std::function<T*()> factory = DefaultMake) : factory_(factory) {}
//...details irrelevant
};
It is possible to "peel" function argument type using:
void foo_double(double a)
{
}
void foo_int(int a)
{
}
template <class R, class A0>
void bar(R (*fp)(A0))
{
// Do something related with A0
}
int main()
{
bar(foo_double); // A0 is double
bar(foo_int); // A0 is int
}
Is it possible to do the same "argument type peeling" to a class constructor function?
Edit:
I believe I didn't explain myself clearly in the original code snippet. Here is the complete scenario.
I have multiple classes C1,...,Cn which I need to expose to python as functions. Lets assume all classes have a common void Run() method. However, the constructors of these classes accept different arguments. To expose functions to python I use boost.python which automatically exports function to an appropriate python function while handling all type conversions (mostly primitives).
My first solution was:
class C1
{
public:
C1() {}
void Run();
};
class C2
{
public:
C2(double a) {}
void Run();
};
template <class T>
void python_wrapper()
{
T instance();
instance.Run();
}
template <class T, class A0>
void python_wrapper(A0 a0)
{
T instance(a0);
instance.Run();
}
BOOST_PYTHON_MODULE(_pythonmodule)
{
// This is boost.python stuff
python::def("f1", python_wrapper<C1>);
python::def("f2", python_wrapper<C2, double>);
}
And... It works.
What I am trying to accomplish now is to use python_wrapper<C2> instead of python_wrapper<C2, double> while inferring the constructor argument types.
As I showed in the original post. I could accomplish something similar if I was wrapping functions instead of classes.
There is no way of deducing a type's constructor's arguments.
C++98/03 and C++11 specifications explicitly list the context in which type deduction may occur (refer to § 14.8.2 and its subsections). Deduction is a qualify of life enhancement for template programming, and not mandatory. Anything that can be done through deduction can also be achieved through explicit calls. Thus, in order for deduction to be possible, it would require that one could explicitly provide a constructor to a function template.
However, this is impossible. As noted in § 12.1 of C++98/03 and C++11 specifications, constructors do not have names. Additionally, § 12.1.12 of C++98/03 and § 12.1.10 of C++11 state that the address of a constructor shall not be taken. Thus, there is no way to provide an identifier; therefore, deduction cannot occur.
With deduction being impossible, it may be worth considering alternative solutions. Each solution will have its own sets of pros and cons, but all of them will require that the argument types be explicitly listed in some context outside of the constructor:
Provide the constructor's argument types to a function template.
Pros:
Fairly simple.
Cons:
The association between the type and the type's constructor's argument types is not very visible.
The association is not reusable. For example, the association would need to be duplicated if passing it to multiple function templates or class templates.
Required for every type that has a constructor with an arity of 1 or greater.
Maintain the association with a type trait.
Pros:
Reusable.
The association between the type and the type's constructor's argument types is more visible.
Not overly complicated.
Cons:
Coding is slightly more complex than providing the association directly to a function template.
Required for every type that has a constructor with an arity of 1 or greater.
Create a factory function for each type.
Pros:
Very simple.
Reusable.
The association between the type and the type's constructor's argument types is very visible.
Cons:
Required for every type, even if the arity is 0. This could be mitigated with an invasive factory functions, as there will be no ambiguities due to scope. For a non-invasive factory functions, there may be collisions on signatures, so the function names must be unique.
Heavy use of meta-programming to have a vector of constructor argument types. Template code would then iterate over the growing list trying to identify a workable match.
Pros:
If types have similar constructors, then a single entry in the vector may serve as a workable match for multiple types.
Cons:
Much more complex.
May require modifying compiler arguments to support template depth.
Given the situation described for your environment:
There are many classes.
Some already exists and shouldn't be changed.
More of these are written on a daily basis.
The constructors are unique.
When factored with the C++ specification, I believe we have defined a Kobayashi Maru. You will have to weight out the pros and cons to determine what approach can be adapted for your environment. The simplest approach may already be the one you have in place, as it only requires a single location for code to change as more types are created.
Nevertheless, here is an approach using a type trait that provides information about a type's constructor in a noninvasive manner. Without C++11 capabilities, such as variadic templates, there is a bit of boilerplate code. Additionally, the implementation may not cover all cases, such as multiple constructors.
Using the classes presented in the original question:
class C1
{
public:
C1();
void Run();
};
class C2
{
public:
C2(double a);
void Run();
};
A template that represents constructor's traits will be used. I am using a type-list provided by Boost.MPL to represent a constructor's argument types. The default constructor_traits indicates no arguments are required.
/// #brief constructor_traits is a type_trait that is used to noninvasively
/// associated T with constructor meta information, such as T'
/// constructor's argument types.
///
/// For example, if Foo has a constructor that accepts a single
/// integer, then constructor_traits<Foo>::type should be
/// boost::mpl::vector<int>.
template <typename T>
struct constructor_traits
{
typedef boost::mpl::vector<> type;
};
This trait is then specialized for types with constructors that accept arguments, such as C2.
/// Specialize constructor_traits for C2 to indicate that its constructor
/// accepts a double.
template <>
struct constructor_traits<C2>
{
typedef boost::mpl::vector<double> type;
};
The boost::mpl::vector is a list of types that represents the constructor's arguments. It provides random access via boost::mpl::at. To provide a slightly cleaner access to elements, a helper type is introduced:
/// #brief Helper type that makes getting the constructor argument slightly
/// easier.
template <typename Vector,
std::size_t Index>
struct get_constructor_arg
: boost::mpl::at<Vector, boost::mpl::int_<Index> >
{};
When exposing the functions to Boost.Python, the desired syntax is to only provide a single type. Either function templates or class templates can be used to solve this problem. I have decided to use class templates, as it reduces some of the boilerplate code.
/// #brief runner type is used to provide a static run function that
/// will delegate the construction and running of type T based
/// on T's constructor_traits.
template <typename T,
typename Args = typename constructor_traits<T>::type,
std::size_t = boost::mpl::size<Args>::value>
struct runner
{
static void run()
{
T().Run();
}
};
This template is then specialized for the amount of arguments the constructor accepts. The following is specialized to accept one argument. This is determined by the 1 in the template argument list of the specialization.
/// Specialization for runner for types with have a single argument
/// constructor.
template <typename T,
typename Args>
struct runner<T, Args, 1>
{
static void run(typename get_constructor_arg<Args, 0>::type a0)
{
T(a0).Run();
}
};
Function templates could also be used to solve this problem. I decided to use class templates because:
No need for SFINAE. Would need to use enable_if constructs to select the correct template.
Being able to provide default template arguments with a class template prevents the need to obtain the constructor_trait multiple times.
The resulting Boost.Python calls would look like:
BOOST_PYTHON_MODULE(_pythonmodule)
{
boost::python::def("f1", &runner<C1>::run);
boost::python::def("f2", &runner<C2>::run);
}
Here is the complete code:
#include <iostream>
#include <boost/mpl/vector.hpp>
#include <boost/python.hpp>
class C1
{
public:
C1() {}
void Run() { std::cout << "run c1" << std::endl; }
};
class C2
{
public:
C2(double a) : a_(a) {}
void Run() { std::cout << "run c2: " << a_ << std::endl;}
private:
double a_;
};
/// #brief constructor_traits is a type_trait that is used to noninvasively
/// associated T with constructor meta information, such as T'
/// constructor's argument types.
///
/// For example, if Foo has a constructor that accepts a single
/// integer, then constructor_traits<Foo>::type should be
/// boost::mpl::vector<int>.
template <typename T>
struct constructor_traits
{
typedef boost::mpl::vector<> type;
};
/// Specialize constructor_traits for C2 to indicate that its constructor
/// accepts a double.
template <>
struct constructor_traits<C2>
{
typedef boost::mpl::vector<double> type;
};
/// #brief Helper type that makes getting the constructor argument slightly
/// easier.
template <typename Vector,
std::size_t Index>
struct get_constructor_arg
: boost::mpl::at<Vector, boost::mpl::int_<Index> >
{};
/// #brief runner type is used to provide a static run function that
/// will delegate the construction and running of type T based
/// on T's constructor_traits.
template <typename T,
typename Args = typename constructor_traits<T>::type,
std::size_t = boost::mpl::size<Args>::value>
struct runner
{
static void run()
{
T().Run();
}
};
/// Specialization for runner for types with have a single argument
/// constructor.
template <typename T,
typename Args>
struct runner<T, Args, 1>
{
static void run(typename get_constructor_arg<Args, 0>::type a0)
{
T(a0).Run();
}
};
BOOST_PYTHON_MODULE(example)
{
boost::python::def("f1", &runner<C1>::run);
boost::python::def("f2", &runner<C2>::run);
}
And the test output:
>>> import example
>>> example.f1()
run c1
>>> example.f2(3.14)
run c2: 3.14
You cannot take the address of a constructor (C++98 Standard 12.1/12 Constructors - "12.1-12 Constructors - "The address of a constructor shall not be taken.")
If all classes share a base class then you could make a factory, but without C++11 variadic templates I don't know of a way to do the argument forwarding.
template <typename type>
static type* construct(){
return new type();
}
auto value = &construct<int>;
You now have a bindable function that when called, produces an type*
auto value = &construct<int>;
int* newInt = (*value)();
delete newInt;
To allow for varying constructors inputs, this uses C++11
template <typename type>
class constructor {
public:
template<typename ...Args>
static std::shared_ptr<type> alloc(Args&& ...args){
return std::shared_ptr<type>(new type(std::forward<Args>(args)...));
}
// placement new
template<typename ...Args>
static std::shared_ptr<type> realloc( std::shared_ptr<type>& object,Args&& ...args){
(new (&(*object)) type(std::forward<Args>(args)...));
return object;
}
};
class fooBar{
public:
fooBar(int x,float f){
}
};
typedef std::shared_ptr<fooBar> fooBarPtr;
Usage:
fooBarPtr a = constructor<fooBar>::alloc(5,0.0f);
Or this might be closer to what the op wants.
class fooy{
int _x = 0;
public:
fooy(int argCount, va_list& list){
if( argCount > 0){
_x = va_arg(list, int);
}
}
};
template <typename type>
std::shared_ptr<type> alloc(int argCount,...) {
va_list list;
va_start(list, argCount);
auto result = std::shared_ptr<type>( new type(argCount,list) );
va_end(list);
return result;
}
Usage:
auto foo1 = alloc<fooy>(0); // passing zero args
auto foo2 = alloc<fooy>(1,1234); // passing one arg
Since you don't want to change the existing classes, there's no way to automate the deduction for those classes within C++. You can do it outside C++ for those classes by extracting the signature information from the source code. This extraction can be done manually or automated by a script or even by a C++ program.
For each existing class E, use the extracted information to define a specialization of a class template that defines a static member function func that passes its argument(s), if any, to constructor of class E and invokes the Run method.
For new classes, simply require them to define func, and let the class template default to using the existing func.
Then the general Python wrapper definition code can infer arguments for func, which you have shown you know how to do.
This means the folks who define the classes just need to start adding func for new such classes.
At a slightly higher level, I think it would be worth using some time on involving the relevant people and finding out how an ungood design could be adopted and entrenched by having a zillion classes defined. With the goal of preventing that from happening again in the future. How to deal with that would depend, I think, on how it happened.
I'm not sure how this will interact with python::def, but in general this is what variadic templates are for:
struct C1{
C1(){}
void run(){}
};
struct C2{
C2(int){}
void run(){}
};
template<typename CLASS, typename... PARAMS>
void call(PARAMS... params) {
CLASS inst(params...);
inst.run();
}
main() {
call<C1>();
call<C2>(42);
}
It's c++11, but supported in gcc since version 4.3
This problem is based on code that works for me on GCC-4.6 but not for another user with CLang-3.0, both in C++0x mode.
template <typename T>
struct MyBase
{
//protected:
T m;
template <typename Args...>
MyBase( Args&& ...x ) : m( std::forward<Args>(x)... ) {}
};
An object of MyBase can take any list of constructor arguments, as long as T supports that construction signature. The problem has to do with the special-member functions.
IIUC, the constructor template cancels the automatically-defined default constructor. However, since the template can accept zero arguments, it will act as an explicitly-defined default constructor (as long as T is default-constructible).
IIUC, determination of a class' copy-construction policy ignores constructor templates. That means in this case that MyBase will gain an automatically-defined copy constructor (as long as T is copyable) that'll channel T copy-construction.
Apply the previous step for move-construction too.
So if I pass a MyBase<T> const & as the sole constructor argument, which constructor gets called, the forwarding one or the implicit copying one?
typedef std::vector<Int> int_vector;
typedef MyBase<int_vector> VB_type;
int_vector a{ 1, 3, 5 };
VB_type b{ a };
VB_type c{ b }; // which constructor gets called
My user's problem was using this in as a base class. The compiler complained that his class couldn't synthesize an automatically-defined copy constructor, because it couldn't find a match with the base class' constructor template. Shouldn't it be calling MyBase automatic copy-constructor for its own automatic copy-constructor? Is CLang in error for coming up with a conflict?
I'm just in the bar with Richard Corden and between us we concluded that the problem has nothing to do with variadic or rvalues. The implicitly generated copy construct in this case takes a MyBase const& as argument. The templated constructor deduced the argument type as MyBase&. This is a better match which is called although it isn't a copy constructor.
The example code I used for testing is this:
#include <utility>
#include <vector>i
template <typename T>
struct MyBase
{
template <typename... S> MyBase(S&&... args):
m(std::forward<S>(args)...)
{
}
T m;
};
struct Derived: MyBase<std::vector<int> >
{
};
int main()
{
std::vector<int> vec(3, 1);
MyBase<std::vector<int> > const fv1{ vec };
MyBase<std::vector<int> > fv2{ fv1 };
MyBase<std::vector<int> > fv3{ fv2 }; // ERROR!
Derived d0;
Derived d1(d0);
}
I needed to remove the use of initializer lists because this isn't supported by clang, yet. This example compiles except for the initialization of fv3 which fails: the copy constructor synthesized for MyBase<T> takes a MyBase<T> const& and thus passing fv2 calls the variadic constructor forwarding the object to the base class.
I may have misunderstood the question but based on d0 and d1 it seems that both a default constructor and a copy constructor is synthesized. However, this is with pretty up to date versions of gcc and clang. That is, it doesn't explain why no copy constructor is synthesized because there is one synthesized.
To emphasize that this problem has nothing to do with variadic argument lists or rvalues: the following code shows the problem that the templated constructor is called although it looks as if a copy constructor is called and copy constructors are never templates. This is actually somewhat surprising behavior which I was definitely unaware of:
#include <iostream>
struct MyBase
{
MyBase() {}
template <typename T> MyBase(T&) { std::cout << "template\n"; }
};
int main()
{
MyBase f0;
MyBase f1(const_cast<MyBase const&>(f0));
MyBase f2(f0);
}
As a result, adding a variadic constructor as in the question to a class which doesn't have any other constructors changes the behavior copy constructors work! Personally, I think this is rather unfortunate. This effectively means that the class MyBase needs to be augmented with copy and move constructors as well:
MyBase(MyBase const&) = default;
MyBase(MyBase&) = default;
MyBase(MyBase&&) = default;
Unfortunately, this doesn't seem to work with gcc: it complains about the defaulted copy constructors (it claims the defaulted copy constructor taking a non-const reference can't be defined in the class definition). Clang accepts this code without any complaints. Using a definition of the copy constructor taking a non-const reference works with both gcc and clang:
template <typename T> MyBase<T>::MyBase(MyBase<T>&) = default;
I've personally had the problem with GCC snapshots for quite some time now. I've had trouble figuring out what was going on (and if it was allowed at all) but I came to a similar conclusion as Dietmar Kühl: the copy/move constructors are still here, but are not always preferred through the mechanics of overload resolution.
I've been using this to get around the problem for some time now:
// I don't use std::decay on purpose but it shouldn't matter
template<typename T, typename U>
using is_related = std::is_same<
typename std::remove_cv<typename std::remove_reference<T>::type>::type
, typename std::remove_cv<typename std::remove_reference<U>::type>::type
>;
template<typename... T>
struct enable_if_unrelated: std::enable_if<true> {};
template<typename T, typename U, typename... Us>
struct enable_if_unrelated
: std::enable_if<!is_related<T, U>::value> {};
Using it with a constructor like yours would look like:
template<
typename... Args
, typename = typename enable_if_unrelated<MyBase, Args...>::type
>
MyBase(Args&&... args);
Some explanations are in order. is_related is a run off the mill binary trait that checks that two types are identical regardless of top-level specifiers (const, volatile, &, &&). The idea is that the constructors that will be guarded by this trait are 'converting' constructors and are not designed to deal with parameters of the class type itself, but only if that parameter is in the first position. A construction with parameters e.g. (std::allocator_arg_t, MyBase) would be fine.
Now I used to have enable_if_unrelated as a binary metafunction, too, but since it's very convenient to have perfectly-forwarding variadic constructors work in the nullary case too I redesigned it to accept any number of arguments (although it could be designed to accept at least one argument, the class type of the constructor we're guarding). This means that in our case if the constructor is called with no argument it is not SFINAE'd out. Otherwise, you'd need to add a MyBase() = default; declaration.
Finally, if the constructor is forwarding to a base another alternative is to inherit the constructor of that base instead (i.e. using Base::Base;). This is not the case in your example.
I upvoted Dietmar's answer because I totally agree with him. But I want to share a "solution" I was using some time earlier to avoid these issues:
I intentionally added a dummy parameter to the variadic constructor:
enum fwd_t {fwd};
template<class T>
class wrapper
{
T m;
public:
template<class...Args>
wrapper(fwd_t, Args&&...args)
: m(std::forward<Args>(args)...)
{}
};
:::
int main()
{
wrapper<std::string> w (fwd,"hello world");
}
Especially since the constructor would accept anything without this dummy parameter, it seems appropriate to make user code explicitly choose the correct constructor by (sort of) "naming" it.
It might not be possible in your case. But sometimes you can get away with it.
I'm trying to use decltype in the late specified return of a member function in a CRTP base class and it's erroring with: invalid use of incomplete type const struct AnyOp<main()::<lambda(int)> >.
template<class Op>
struct Operation
{
template<class Foo>
auto operator()(const Foo &foo) const ->
typename std::enable_if<is_foo<Foo>::value,
decltype(static_cast<const Op*>(nullptr)->call_with_foo(foo))>::type
{
return static_cast<const Op*>(this)->call_with_foo(foo);
}
};
template<class Functor>
struct AnyOp : Operation<AnyOp<Functor> >
{
explicit AnyOp(Functor func) : func_(func) {}
template<class Foo>
bool call_with_foo(const Foo &foo) const
{
//do whatever
}
private:
Functor func_;
};
I'm basically trying to move all of the sfinae boiler plate into a base class so I don't need to repeat it for every Operation that I create (currently each operation has 6 different calls and there are ~50 operations so there is quite a lot of repetition with the enable_if's).
I've tried a solution which relied on overloading but one of the types which may be passed is anything that's callable(this can be a regular functor from C++03 or a C++0x lambda) which I bound to a std::function, unfortunately, the overhead from std::function, although very minimal, actually makes a difference in this application.
Is there a way to fix what I currently have or is there a better solution all together to solve this problem?
Thanks.
You are, as another answer describes already, trying to access a member of a class in one of the class' base class. That's going to fail because the member is yet undeclared at that point.
When it instantiates the base class, it instantiates all its member declarations, so it needs to know the return type. You can make the return type be dependent on Foo, which makes it delay the computation of the return type until Foo is known. This would change the base class like the following
// ignore<T, U> == identity<T>
template<typename T, typename Ignore>
struct ignore { typedef T type; };
template<class Op>
struct Operation
{
template<class Foo>
auto operator()(const Foo &foo) const ->
typename std::enable_if<is_foo<Foo>::value,
decltype(static_cast<typename ignore<const Op*, Foo>::type>(nullptr)->call_with_foo(foo))>::type
{
return static_cast<const Op*>(this)->call_with_foo(foo);
}
};
This artificially makes the static_cast cast to a type dependent on Foo, so it does not immediately require a complete Op type. Rather, the type needs to be complete when operator() is instantiated with the respective template argument.
You are trying to refer to a member of a class from one of its own base classes, which will fail since the class's body doesn't exist within its base class. Can you pass the logic for computing the return type of call_with_foo as a metafunction to the base class? Is that logic ever going to be complicated?
Another option, depending on how much flexibility you have in changing your class hierarchy (and remember that you have template typedefs), is to have the wrapper inherit from the implementation class rather than the other way around. For example, you can write a AddParensWrapper<T> that inherits from T and has operator() that forwards to T::call_with_foo. That will fix the dependency problem.