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
Related
I am trying to write a class template that uses a parameter-pack and implements a member function for each type contained in the parameter-pack.
This is what I have so far:
template <typename...T>
class Myclass {
public:
void doSomething((Some_Operator_to_divorce?) T) {
/*
* Do Something
*/
std::cout << "I did something" << std::endl;
}
};
My goal is to have a class template that can be used in the following way:
Myclass<std::string, int, double> M;
M.doSomething("I am a String");
M.doSomething(1234);
M.doSomething(0.1234);
Where the class template mechanism will create an implementation for a doSomething(std::string x), a doSomething(int x) and a doSomething(double x) member function but not a doSomething(std::string x, int i, double f) member function.
I found a lot of examples in the web on the usability of parameter-packs, but I could not figure out if it can be used for my purpose, or if I totally misunderstood for what a parameter-pack can be used.
I thought that I need to unpack the parameter-pack but, after reading a lot of examples about unpacking parameter packs, I believe that this is not the right choice and it has a complete different meaning.
So, therefore, I am looking for a operation to "divorce" a parameter-pack.
There is no "operator" specifically that supports this, but what you're requesting can be done in a few different ways, depending on your requirements.
The only way to "extract" T types from a parameter pack of a class template with the purpose of implementing an overload-set of functions is to implement it using recursive inheritance, where each instance extracts one "T" type and implements the function, passing the rest on to the next implementation.
Something like:
// Extract first 'T', pass on 'Rest' to next type
template <typename T, typename...Rest>
class MyClassImpl : public MyClassImpl<Rest...>
{
public:
void doSomething(const T&) { ... }
using MyClassImpl<Rest...>::doSomething;
};
template <typename T>
class MyClassImpl<T> // end-case, no more 'Rest'
{
public:
void doSomething(const T&) { ... }
};
template <typename...Types>
class MyClass : public MyClassImpl<Types...>
{
public:
using MyClassImpl<Types...>::doSomething;
...
};
This will instantiate sizeof...(Types) class templates, where each one defines an overload for each T type.
This ensures that you get overload semantics -- such that passing an int can call a long overload, or will be ambiguous if there are two competing conversions.
However, if this is not necessary, then it'd be easier to enable the function with SFINAE using enable_if and a condition.
For exact comparisons, you could create an is_one_of trait that only ensures this exists if T is exactly one of the types. In C++17, this could be done with std::disjunction and std::is_same:
#include <type_traits>
// A trait to check that T is one of 'Types...'
template <typename T, typename...Types>
struct is_one_of : std::disjunction<std::is_same<T,Types>...>{};
Alternatively, you may want this to only work if it may work with convertible types -- which you might do something like:
template <typename T, typename...Types>
struct is_convertible_to_one_of : std::disjunction<std::is_convertible<T,Types>...>{};
The difference between the two is that if you passed a string literal to a MyClass<std::string>, it will work with the second option since it's convertible, but not the first option since it's exact. The deduced T type from the template will also be different, with the former being exactly one of Types..., and the latter being convertible (again, T may be const char*, but Types... may only contain std::string)
To work this together into your MyClass template, you just need to enable the condition with SFINAE using enable_if:
template <typename...Types>
class MyClass
{
public:
// only instantiates if 'T' is exactly one of 'Types...'
template <typename T, typename = std::enable_if_t<is_one_of<T, Types...>::value>>
void doSomething(const T&) { ... }
// or
// only instantiate if T is convertible to one of 'Types...'
template <typename T, typename = std::enable_if_t<is_convertible_to_one_of<T, Types...>::value>>
void doSomething(const T&) { ... }
};
Which solution works for you depends entirely on your requirements (overload semantics, exact calling convension, or conversion calling convension)
Edit: if you really wanted to get complex, you can also merge the two approaches... Make a type trait to determine what type would be called from an overload, and use this to construct a function template of a specific underlying type.
This is similar to how variant needs to be implemented, since it has a U constructor that considers all types as an overload set:
// create an overload set of all functions, and return a unique index for
// each return type
template <std::size_t I, typename...Types>
struct overload_set_impl;
template <std::size_t I, typename T0, typename...Types>
struct overload_set_impl<I,T0,Types...>
: overload_set_impl<I+1,Types...>
{
using overload_set_impl<I+1,Types...>::operator();
std::integral_constant<std::size_t,I> operator()(T0);
};
template <typename...Types>
struct overload_set : overload_set_impl<0,Types...> {};
// get the index that would be returned from invoking all overloads with a T
template <typename T, typename...Types>
struct index_of_overload : decltype(std::declval<overload_set<Types...>>()(std::declval<T>())){};
// Get the element from the above test
template <typename T, typename...Types>
struct constructible_overload
: std::tuple_element<index_of_overload<T, Types...>::value, std::tuple<Types...>>{};
template <typename T, typename...Types>
using constructible_overload_t
= typename constructible_overload<T, Types...>::type;
And then use this with the second approach of having a function template:
template <typename...Types>
class MyClass {
public:
// still accept any type that is convertible
template <typename T, typename = std::enable_if_t<is_convertible_to_one_of<T, Types...>::value>>
void doSomething(const T& v)
{
// converts to the specific overloaded type, and call it
using type = constructible_overload_t<T, Types...>;
doSomethingImpl<type>(v);
}
private:
template <typename T>
void doSomethingImpl(const T&) { ... }
This last approach does it two-phase; it uses the first SFINAE condition to ensure it can be converted, and then determines the appropriate type to treat it as and delegates it to the real (private) implementation.
This is much more complex, but can achieve the overload-like semantics without actually requiring recursive implementation in the type creating it.
I have 2 classes that both have single-argument templated constructors. One is meant as a catch all for integer types, and in the other class it's for binding any iterable object. I have two overloads for a particular function that will each of these types. If I call the function with an integer type or a string, or something that would work for at least one of the classes, I get an error about call ambiguity.
#include <string>
class A {
public:
template <typename Iterable>
A(Iterable it) : s(it.begin(), it.end()) {}
private:
std::string s;
};
class B {
public:
template <typename Integer>
B(Integer i) : i(i + 1) {}
private:
int i;
};
void Use(A a)
{
// some thing
}
void Use(B b)
{
// some other thing
}
int main(void)
{
Use(0);
return 0;
}
The compiler doesn't seem to be looking far enough into the set of polymorphisms to determine that there really only is one possible solution. Could this be because template are 'resolved' before function overloads? How do I give the compiler some help?
The compiler doesn't seem to be looking far enough into the set of polymorphisms to determine that there really only is one possible solution.
Note that overload resolution is performed based on the signature of function templates, including function names, function parameters, template parameters, etc; but not implementations (e.g. the function body), which won't be examined during overload resolution.
You could apply SFINAE to put restrictions on types which could be accepted by constructor templates, by adding another template parameter with default value. e.g.
template <typename Iterable, typename = std::void_t<decltype(std::declval<Iterable>().begin()),
decltype(std::declval<Iterable>().end())>>
A(Iterable it) : s(it.begin(), it.end()) {}
and
template <typename Integer, typename = std::void_t<decltype(std::declval<Integer>() + 1)>>
B(Integer i) : i(i + 1) {}
LIVE
The compiler doesn't regard the implementation of the method when follows the SFINAE rules. In other words it sees the declaration of the class A constrator that accepts a single argument.
If you wish SFINAE to eliminate this choice, you need to move the expression that fails the substitution to the function signature.
I've looked for questions on this subject, and although there are similar ones, none really address my question. So, here I go.
Suppose I have a template type F, and I declare a series of specializations as member variables of another object:
F<A> a;
F<B> b;
.
.
.
Later, I'd like to iterate over these and perform an operation that is defined on any F instance.
So my impulse is to create a std::list< F> but this does not work.
Is there a way to create a list of objects of type F, that is, without specifying the template parameter?
My hunch is no, not in C++, but hoping I am wrong.
Unless all F<X> derive from some common base-class independent of X, this is only be possible using type erasure or heterogeneous containers.
If they all inherit from Foo, then of course you can iterate over them as as Foo&/Foo*, but I guess you knew that.
If they have different types the standard-containers cannot hold them, because they are homogeneous - all elements have the same type. There is probably some library with heterogeneous containers, but in the STL, you can only emulate this with std::variant or std::any.
The last way I could imagine this works out - I don't recommend this - is by creating the enclosing class as a derived class of the F<X>s (variadic template) and encoding the invocations into the hierarchy, s.t. every Fsfoo` is called
Since this is somewhat more involved here is a sample:
#include <iostream>
template <class X>
class Foo {
X mem;
public:
explicit Foo(X arg) : mem(arg) {}
void foo() {
std::cout << mem;
}
};
template <class X, class ...Xs> class Holder;
template <class X>
class Holder<X> {
X member;
public:
Holder(X arg) : member(std::forward<decltype(arg)>(arg)) {}
void call() {
member.foo();
}
};
template <class X, class ...Ys>
class Holder : public Holder<Ys...> {
X member;
public:
Holder(X arg, Ys ...args) : Holder<Ys...>(std::forward<decltype(args)>(args)...), member(std::forward<decltype(arg)>(arg)) { }
void call() {
member.foo();
Holder<Ys...>::call();
}
};
int main() {
// omitting the template-args requires c++17 deduction guides
Holder holder(Foo(4), Foo(" Hello "), Foo(7L), Foo(" World "));
holder.call();
std::cout << std::endl;
}
You maybe able to guess, that this is typically not what you want, because it is super-complex. I actually omitted some things like perfectly forwarding the arguments to keep it somewhat minimal, s.t. one can hopefully understand the concept.
Unfortunately, the answer is NO. In C++ you can't have a container of heterogeneous unrelated objects, and different instantiations of the same template are unrelated.
The only way to make it work is to use some form of the type erasure. The most idiomatic is to use inheritance and virtual functions, and put pointers to base object into your list.
As far as C++ is concerned, two different template instantiations of a template class or struct are completely separate types and have no relation to each other whatsoever. For example, a std::vector<int> and a std::vector<char> are separate types; neither derives from the other or from any common base. The fact that both types arose from instantiations of the same template does not create a semantic relationship between the types. In that sense (and that sense only) you might think of templates like preprocessor macros which are expanded before compilation to declare new and unrelated types.
But, you can create such a relationship yourself using inheritance, just as you would with any non-template types:
#include <iostream>
struct foo_base {
virtual void print() = 0;
};
template <typename T>
struct foo : foo_base {
foo(T data) : data(data) {}
virtual void print() override {
std::cout << data << std::endl;
}
private: T data;
};
void example() {
foo<int> f(42);
f.print();
}
Here, a foo<int> and a foo<char> are separate types (as distinct instantiations of the foo<> template), but all foo<> instantiations derive from foo_base. (Unless, of course, you provide an explicit specialization of foo<> which does not derive from foo_base...)
I'm currently implementing a dataset helper class template storing floating point values (Scalar) in a dynamically sized Eigen::Matrix constructed from a vector of different values types (Element) additionally storing a reference to this input vector. Now i want to partially specialize the constructor in the vector value type remaining a template in the scalar type to be explicitly instantiated.
Unfortunately i'm getting "unable to match function definition to an existing declaration" on VS 2010. The code is as simple as:
template <class Scalar, class Element> struct DataSet
{
DataSet(std::vector<Element> const & source);
// several generic member functions here ...
Eigen::Matrix<Scalar, ... > data;
std::vector<Element> const & source;
};
template<class Scalar>
DataSet<Scalar, SomeClass>::DataSet(std::vector<SomeClass> const & input)
{
// special impl for Element==SomeClass ...
}
SomeClass should be automatically be figured out by the compiler, when done right but i tried all meaningful combinations but still getting:
*.cpp(79) C2244 : unable to match function definition to an existing declaration
see declaration of 'DataSet<Scalar, Element>::DataSet'
I was not able to find a matching example by searching the internet yet. Thanks in advance!
EDIT:
To make it more specific, in my real world case i want to be able to define several partial specializations to the constructor with different types for Element e.g:
template<Scalar>
DataSet<Scalar, FirstClass>::DataSet(std::vector<FirstClass> const & first)
: data()
, source(first)
{
// special impl here ...
}
template<Scalar>
DataSet<Scalar, std::shared_ptr<SecondClass> >::DataSet(std::vector<std::shared_ptr<SecondClass> > const & second)
: data()
, source(second)
{
// special impl here ...
}
Redeclaring/specializing the class completely to a certain typename is not desired. Then there is little use to be a template at all. I want the solution as it is, otherwise there might be other strategies to my problem.
FIN:
Since it looks like not being possible to share the type Element between class template and constructor by only specializing the constructor (which is somehow related to an implicit specialization of the class) i removed the reference source from the class template entirely and copied the needed information into a generic container and implemented the constructors via overloads.
When defining your constructor, you didn't explicitly provide both template arguments for its class. That would need to be revised as follows:
template<typename T_Scalar, typename T_Element>
DataSet<T_Scalar, T_Element> // template args for type
::DataSet(std::vector<T_Element> const &input) // but none for constructor
{
// stuff
}
Tangentially related: Unlike methods, template arguments for classes cannot be deduced from constructor calls. That is: until C++17 comes around! woo!
The next stumbling block you faced is that template specialisations do not 'inherit' members from their primary template. It is somewhat intuitive to assume they would, but it's just not so. Until I find an official rationale, I presume it's because template arguments might make certain members totally inapplicable to a specialisation, rendering implicit 'inheritance' problematic. If so, it would've been decided to require full redeclaration / not judged worthwhile to add arcane syntax to specify which primary 'base' members are 'inherited'... when you can simply use real inheritance to ensure they are.
Anyway, what that means is that to get a partial specialisation, you need to declare the whole thing - in this case, the class and its constructor - before you can specialise that constructor's definition. You hadn't declared these ahead of time, so the compiler rightly complained that it couldn't see a declaration.
// Define specialised class
template<typename T_Scalar>
class DataSet<T_Scalar, SomeClass>
{
public:
// Declare its ctor
DataSet(std::vector<SomeClass> const &);
}
// Implement its ctor
template<typename T_Scalar>
DataSet<T_Scalar, SomeClass> // complete template args
::DataSet(std::vector<SomeClass> const &input)
{
// stuff
}
See my working example of an equivalent template class, showing general vs. specialised instantiations.
To add to your original confusion, which is fair! - note that out-of-line definitions can get very complicated indeed if a template class itself contains a template function, because then you need 2 template clauses, e.g.
template<typename TA, typename TB>
class Widget {
template<typename TC>
void accept_gadget(TC &&gadget);
};
template<typename TA, typename TB>
template<typename TC>
Widget<TA, TB>
::accept_gadget(TC &&gadget)
{
/* ... */
}
Something that will help a lot in many contexts, especially including such out-of-line template definitions, is if the proposal to allow namespace class is accepted in a future version. Very sad this didn't make it into C++17... and very odd that it was ever missing in the 1st place!
According to §14.7.3.16:
In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well.
Still, you can use std::enable_if to partial-specialize your contructor:
template <class Scalar, class Element> struct DataSet
{
template <class T>
DataSet(std::vector<T> const & input, std::enable_if_t<!std::is_same<T, SomeClass>{}> * = nullptr) {
std::cout << "Element\n";
}
template <class T>
DataSet(std::vector<T> const & input, std::enable_if_t<std::is_same<T, SomeClass>{}> * = nullptr) {
std::cout << "SomeClass\n";
}
};
But this way is restrictive:
all your conditions must be exclusives
you'll have to modify the code of your class for every new class you want to handle.
Instead, I'd advise you to use a template helper structure:
DataSet(std::vector<Element> const & input) {
Helper<Element>::do_it(input);
}
that you can specialize as you want:
template <class Element>
struct Helper {
static void do_it(std::vector<Element> const & input) {
std::cout << "General form with Element\n";
}
};
template<>
struct Helper<SomeClass> {
static void do_it(std::vector<SomeClass> const & input) {
std::cout << "SomeClass\n";
}
};
template<>
struct Helper<SomeOtherClass> {
static void do_it(std::vector<SomeOtherClass> const & input) {
std::cout << "SomeOtherClass\n";
}
};
...
Lets say hypothetically that I am making a game and in that game there are spawning points class SpawnArea for monsters' classes that inherit from class Monster. Would it be correct to use a template knowing that I am not expecting just any class and Spawn will only accept a specific subset of classes? I would like to use a template cause it's the only way I'm aware of to pass a class type as argument for the purpose of constructing instances of a specific class. Is there any more elegant way to write a class who's instances are used to construct multiple instances of some other specific class?
I read this:
Make a template accept a specific class/family of classes?
It did not discuss the issue of constructing instances of a specific set of classes.
It's quite common, actually almost all templates have certain requirements towards their arguments. Those are usually implicitly clear from how the template parameter is used, but you can improve the error messages by using type traits. In C++11, they are available from the standard library via #include <type_traits>, otherwise look into Boost.TypeTraits.
With C++11, the usage is quite simple when you also use static_assert:
template< typename T >
std::shared_ptr< T > spawn()
{
// make this the first line in your function to get errors early.
// also note that you can use any compile-time check you like.
static_assert( std::is_base_of< Monster, T >::value,
"T is not derived from Monster" );
// the rest of your code follows here.
// ...
// return ...;
}
In case you have to use a template function (which I guess could be done better using factory functions) and your compiler supports c++11 (most current compilers do), you could restrict your template function using type_traits like:
#include <type_traits>
...
template <typename MonsterT,
class = typename std::enable_if<
std::is_base_of<Monster, MonsterT>::value
>::type
>
std::shared_ptr<MonsterT> spawn() { ... }
This way the compiler won't accept
spawn<SomeType>()
if SomeType is not derived of Monster. A way more generic solution would be concepts, however unfortunately they are not part of c++11/c++14 - some people consider the Boost Concept Check library suitable enough for that purpose.
Like I said above using template functions may not be the wisest choice (one of the problems being the tendency to prevent a clear and concise documentation) - just wanted to show a way to "restrict" templates for this use case.
I think using SFINAE to emulate the template constraints of Concepts Lite is useful.
Consider a shape class hierarchy like this:
/* Base class. */
class Shape { /* ... */ };
/* Derived classes. */
class Circle : public Shape { /* ... */ };
class Square : public Shape { /* ... */ };
class Triangle : public Shape { /* ... */ };
Peek into Concepts Lite
First, let's look at a simple usage pattern of constraints in Concepts Lite similar to the examples shown in section 2.1 in N3580:
/* SomeShape concept. */
template <typename T>
concept bool SomeShape() { return std::is_base_of<Shape, T>::value; }
/* T must meet SomeShape concept. */
template <SomeShape T>
double GetArea(const T &shape) { /* ... */ }
which is equivalent to
template <typename T>
requires SomeShape<T>()
double GetArea(const T &shape) { /* ... */ }
Emulation with std::enable_if as the return type.
Now, we can't get the first form which is clearly prettier, but we could emulate the second form with std::enable_if.
/* SomeShape concept. */
template <typename T>
constexpr bool SomeShape() { return std::is_base_of<Shape, T>::value; }
/* Force T to be specified. */
template <bool B, typename T>
using requires = std::enable_if_t<B, T>;
can be used like so:
// Awkward indenting to make it look similar to the second form.
template <typename T>
requires<SomeShape<T>(),
double> GetArea(const T &shape) { /* ... */ }
Multiple constraints
It's easy to compose multiple constraints since the result simply needs to be a compile-time boolean value. Suppose we didn't have std::is_arithmetic available to us, we could either implement it, or if it's only of one-time use, we can just use it inline like so:
template <typename Val>
requires<std::is_integral<Val>::value || std::is_floating_point<Val>::value,
Val> DoubleMe(const Val &val) {
return val + val;
}
Limitations of putting std::enable_if as the return type
Doesn't work for things that don't have a return type such as constructors.
Doesn't work with return type deduction using auto and -> decltype(/* ... */)
NOTE: std::enable_if can go in the template-parameter-list to make it work with constructors and return type deduction, but it doesn't work with variadic templates. If this is your preferred option, check out my answer to this question,
Difference between SFINAE with std::enable_if and static_assert
The important difference between the two is that with std::enable_if, the function does not get considered during overload resolution. So if you know you won't have overloads, you may prefer to simply use static_assert since you'll get a better error message (assuming you choose a better one of course).
Consider the following overloaded functions:
template <typename T>
requires<SomeShape<T>(),
void> Print(const T &shape) {
std::cout << shape << std::endl;
}
void Print(double val) {
std::cout << std::showpoint << val << std::endl;
}
Calling Print(2.0); will of course bind to the void Print(double val); overload. Print(1); also bind to void Print(double val); because void Print(const T &shape); does not get considered for overload resolution and int is implicitly convertible to double.
Now consider what happens if we used static_assert instead.
template <typename T>
void Print(const T &shape) {
static_assert(SomeShape<T>(), "T must be a Shape!");
std::cout << shape << std::endl;
}
void Print(double val) {
std::cout << std::showpoint << val << std::endl;
}
Calling Print(1) this time binds to the first version because void Print(const T &shape); which gets instantiated to void Print(const int &shape) which is a better match than void Print(double val);. We then hit the static_assert which gives us a compile-time error.