suppose I have a lot of classes with their "*Pack" counterparts in naming. For example, if I have a class Moo, I have MooPack, if I have Foo, I also have FooPack.
I want to have a c++ templated function which returns a FooPack from a Foo
template <class X, class XPack>
XPack packify(X input){
...
}
Is it possible to do this without having to specify the template argument? At the moment, this has to be done like the following:
Moo moo;
MooPack mooppey = packify<Moo, MooPack>(moo);
If it only required the Moo template argument, that ugly template specification bit could go away, but apart from using #defines, which isn't really the best solution either, still doesn't do it.
Is there a way, or will I have to wait for c++0x?
You don't have to specify Moo, just MooPack, because moo will deduce the argument for you. However, I'd suggest that you make MooPack a typedef or nested class (called Pack) inside Moo itself, in which case you can easily access it by typename X::Pack inside the template.
class Moo {
public:
class Pack {
...
};
};
template<typename T> typename T::Pack packify(T t) {
...
}
// usage
Moo m;
Moo::Pack p = packify(m);
As the answer by DeadMG already mentioned you don't need to explicitely specify the parameter type as it can be deduced automaticaly (if it's the second instead of the first template parameter). Since you said you can't change the type declarations to form a link between the classes, I would propose the traits route for that (think std::iterator_traits):
template<typename T> struct pack_traits;
template<> struct pack_traits<Moo> { typedef MooPack Pack; };
...//traits for other packifable classes
template<typename T> pack_traits<T>::Pack packify(T val){...}
...
Moo moo;
MooPack mooppey = packify(moo);
This way you can call the function without manually specifying template arguments, without needing to modify the classes themselves.
Related
I am currently seen some c++11 code in the project , where i got little confused with some funky syntax.
below is the code
std::shared_ptr<CommonAPI::Runtime> runtime_AMB = CommonAPI::Runtime::get();
std::shared_ptr<v1::org::table::psa::EthernetProxy<>> amb_consumer ;
amb_consumer = runtime_AMB->buildProxy<v1::org::table::psa::EthernetProxy>();
Here my doubt is "buildProxy" function, it can be simply called why its mention like
buildProxy<v1::org::table::psa::EthernetProxy>() instead of buildProxy()
One more doubt is
shared_ptr<v1::org::table::psa::EthernetProxy<>> here why EthernetProxy<> instead just like v1::org::table::psa::EthernetProxy
May be its easy but i am not aware of c++11 thatmuch
Answer to the first question
Say you have:
struct Foo
{
template <typeename T>
T bar() { return T{}; }
template <typeename T>
T baz(T t) { return 2*t; }
};
To use Foo::bar, you need to provide a template parameter.
Foo foo;
foo.bar<int>(); // OK.
foo.bar(); // Not OK.
If the template parameter can be deduced from the arguments, then you don't need to explicitly specity the template parameter.
foo.baz<int>(10); // OK. Template parameter is explicity.
foo.bar(10); // Also OK. Template parameter is deduced to be int
Answer to the second question
EthernetProxy seems to be a class template with a default template parameter.
Say you have:
template <typename T = int> struct EthernetProxy { ... };
EthernetProxy is not a class, it is a class template. An instatiation of the class template will be a class.
EthernetProxy<double> var1; // OK
EthernetProxy<> var2; // Also OK. The default template parameter int is used.
That's why you can use EthernetProxy<> as a type but not EthernetProxy.
I would like to use an enum argument of a template, to restrict a second argument, a class, to in turn taking an member of the enum as an argument as it's templated parameter. In code, I would expect this to look like:
CObject<EObjectTag, CSubObject<EObjectTag::CAT_A>> cObject;
this should work, however:
CObject<EObjectTag, CSubObject<ENotAnObjectTag::CAT_OTHER>> cObject;
should fail as ENotAnObjectTag::CAT_OTHER is not a element of EObjectTag.
My implementation (attempt) of this, is as follows and bombs out during compilation (on gcc version 4.9.2 (Ubuntu 4.9.2-10ubuntu13)) with the error message:
source.cc:16:45: error: ‘SUBOBJECT_TAG’ was not declared in this scope
struct CObject>
#include <iostream>
#include <typeinfo>
enum class EObjectTag {CAT_A, CAT_B, CAT_OTHER};
// CSubObject
template<class OBJECT_TAG_T, OBJECT_TAG_T OBJECT_TAG>
struct CSubObject { OBJECT_TAG_T m_tTag = OBJECT_TAG; };
// CObject - Forward declaration
template <class SUBOBJECT_TAG_T, template <SUBOBJECT_TAG_T SUBOBJECT_TAG> class SUBOBJECT_T>
struct CObject;
// CObject - Specialization
template <class SUBOBJECT_TAG_T, template <SUBOBJECT_TAG_T SUBOBJECT_TAG> class SUBOBJECT_T>
struct CObject<SUBOBJECT_T<SUBOBJECT_TAG_T, SUBOBJECT_TAG>>
{
public:
SUBOBJECT_T<SUBOBJECT_TAG_T, SUBOBJECT_TAG> m_cSubObject;
};
int main() {
// The aim is that the second object only accepts a tag that
// belongs to EObjectTag
CObject<EObjectTag, CSubObject<EObjectTag::CAT_A>> cObject;
return 0;
}
The final use case for this involves replacing CSubObject with CObject so that we can use recursion to define a hierarchy of tagged objects, which also requires the use of variadic templates to have multiple objects at the same level. For example:
/* EBase, */
CObject</*EBase::BASE,*/ EObject,
CObject<EObject::INIT, EInitObject,
CObject<EInitObject::INIT_FOO>,
CObject<EInitObject::INIT_BAR>,
>,
CObject<EObject::COUNT, ECountObject,
CObject<ECountObject::COUNT_FOO>,
CObject<ECountObject::COUNT_BAR>,
>,
> cMyObjectHierarchy;
The commented out references to EBase (an enum internal to the library) are there to keep the template parameters of CObject consistent, I would plan (if possible) to do this automatically via template specialization or default arguments.
My goals of specifying this hierarchy of objects would in addition include:
Avoid forcing the user of this library to define additional classes
or structs in their program
Leverage compile time checking via the
templating of CObject with an enum, whose functions in turn use that
enum as an argument to a set of functions common to all CObjects
An argument of template <SUBOBJECT_TAG_T SUBOBJECT_TAG> class SUBOBJECT_T is a template, not an instance of a template. CSubObject<blah> cannot match the kind template<...>class, because CSubObject<blah> is a type that is generated by the template, not a template. template<...>class parameters are templates, not types.
In addition, CSubObject is of kind template<class T, T> class, not template<SUBOBJECT_TAG_T>class. It takes two arguments, the first a type, the second a constant of that type: the kind template<SUBOBJECT_TAG_T>class is a template that takes one argument of type SUBOJECT_TAG_T. These are unrelated kinds of template.
Second, you seem to have issues with template specializations. Template specializations are pattern-matching of your primary specialization. They are not "new overloads". So arguments to CObject must first match the kinds of arguments the primary specialization of CObject expects. The stuff within template< blah > are used to pattern match the pattern in the CObject< blah > part of the specialization.
In general, it is conventional to use ALL CAPS only for macros, not for template arguments.
These are all problems with your code in your question. Your code lacks a clear problem statement or question, so the best I can do is describe fixes to your myriad of problems.
You have revised your question a bit.
template<class T, class U>
struct CObject;
template<class T, template<class Q, Q>class Z, T t>
struct CObject< T, Z<T, t> > {
};
live example.
Now, you still have to pass CSubObject<EObjectTag, EObjectTag::CAT_A> as the 2nd parameter.
You could also add a specialization:
template<class T, template<T>class Z, T t>
struct CObject< T, Z<t> > {
};
which, if you had a template<EObjectTag tag> struct Example;, you could CObject< EObjectTag, Example<EObjectTag::bob> > as well.
I made some changes to make it compile. Although I'm not 100% sure if this actually does what you want it to do; I agree with most of what Yakk sais in his answer.
Note: the following will not compile because I deliberately tried to mix a type of one enum with a value of another enum to verify that it indeed triggers a compile-time error, which I think is sort of what you asked for.
#include <iostream>
#include <typeinfo>
enum class EObjectTag {CAT_A, CAT_B, CAT_OTHER};
enum class FObjectTag {DOG_A, DOG_B, DOG_OTHER};
// CSubObject
template<typename OBJECT_TAG_T, OBJECT_TAG_T OBJECT_TAG>
struct CSubObject { OBJECT_TAG_T m_tTag = OBJECT_TAG; };
// CObject - Specialization
template <class SUBOBJECT_TAG_T, SUBOBJECT_TAG_T SUBOBJECT_TAG, template <typename TYPE_T, TYPE_T TYPE> class SUBOBJECT_T>
struct CObject
{
public:
SUBOBJECT_T<SUBOBJECT_TAG_T, SUBOBJECT_TAG> m_cSubObject;
};
int main() {
// The aim is that the second object only accepts a tag that
// belongs to EObjectTag
CObject<EObjectTag, EObjectTag::CAT_A, CSubObject> cObject1;
CObject<EObjectTag, FObjectTag::DOG_B, CSubObject> cObject2;
return 0;
}
The std::function class is templated in such a way that when we want it to wrap a function like the following:
void printInt(int integer)
{
std::cout << int << '\n';
}
We use a std::function<void(int)>. Until recently I thought this was an odd nuance of the class, but a class I found while searching for delegate implementation in C++ uses a similar syntax.
What exactly is void(int), and what do we call it in technical terms? It seems to be the standard way of saying "a function that takes an int, and returns void" in codespeak, but my gut instinct says that's horribly oversimplified.
Secondly, I've noticed that when I see templates using this syntax they use variadic templates to allow multiple function signatures to be matched. From the link above:
template <typename T> class delegate;
template<class R, class ...A>
class delegate<R (A...)>
{
...
What is the reason for declaring the function as such instead of simply using the following:
template<class R, class ...A>
class delegate
{
...
The template parameter to std::function<Signature> is simply the type of a function, i.e., its signature. It uses the same notation as any function declaration except that it isn't named and the name is left out. You may have come across function pointers which use the same notation but the function signature is used for a pointer.
The reason std::function<Signature> (and apparently delegate<Signature>) are implemented using template specialization is to yield a nicer type:
template <typename T> class function;
template <typename R, typename... Args>
class function {
public:
R operator()(Args...);
// ...
};
template <typename R, typename... Args>
class other {
public:
R operator()(Args...);
// ...
};
int main() {
function<int(double, char)> f;
other<int, double, char> o;
}
Since the primary template for function<T> takes one type as argument, using the specialization the argument can be a normal function type. On the other hand, the same isn't done for other<T...> which, thus, gets a list of types.
It is worth nothing that std::function<T> objects can be passed around quite easily without any need to deal with many template arguments: since the function's signature is just a type, this class template takes just one template argument.
I have learned that data structures can be created using templates in the following way:
template<typename T>
struct X {
T weight;
int age;
};
The functions can also use templates in the following way:
template <class T>
T func_name(int age, T human) {
something_here;
}
One of the difference s is that in the first case we use typename while in the second case we use class.
I found code that contains the following:
template<typename S, typename T>
bool is_null(const row<T>& r)
So, what I cannot understand is why we use typename (and not class) in combination with functions. Shouldn't we use class?
In this context, there is no technical difference between the keyword typename and the keyword class. It's just a matter of style. The meaning of your first two code examples would not change one bit if they started with template<class T> struct X and template <typename T> T func_name(int age, T human). (I tend to use class when I mean to imply the template parameter should be a class, and not something like int.)
When template was first introduced, it ONLY allowed the existing keyword class as an indicator "this is a template argument". Since this becomes rather daft when the template argument isn't actually a class (a function pointer, integer type, or some other "not a class" type), the typename was introduced to make it more clear that template<typename T> struct something { T x; }; allows something<int> a; as well as something<name_of_class> a;.
For all intents and purposes, class and typename in the case of template parameters is interchangeable, and it's just a matter of style which you choose to do [most people probably prefer if you stick to one, not mixing the two - or, perhaps use class when the type HAS TO be a class, and typename when it can be "any" type].
In the context of template parameter definitions the keywords typename and class are synonymous.
Just about everyone has a convention they tend to stick with. I personally prefer to always use class here and reserve the typename keyword for its other use.
The other use for typename is to disambiguate a dependent type in a template definition or declaration.
Here is an example from wikipedia:
template <typename T>
void foo(const T& t)
{
// declares a pointer to an object of type T::bar
T::bar * p;
}
struct StructWithBarAsType {
typedef int bar;
};
int main() {
StructWithBarAsType x;
foo(x);
}
If you look closely you will notice in the line T::bar * p;, bar is dependent on a template parameter T which is ambiguous to the compiler as bar can be either a type or a value depending on the context of the type T used for instantiating the template. The default is to treat bar as a value so the meaning would be to multiply T::bar by p which is not what we want.
The solution is to qualify the dependent type with the typename keyword.
typename T::bar * p;
This alerts the compiler to the fact that we intend to treat bar as a type.
There's only one spot where they differ (when declaring template parameters), and that is when using template-templates.
The following is well-defined C++
template <template <typename> class TT> struct example_one {};
while this is not:
template <template <typename> typename TT> struct example_two {};
Since it seems like you're just starting out with C++/templates, this corner case won't concern you for a while :-) Aside from the above, class template, function template, it doesn't matter: typename and class are synonymous.
I want to be able to templatize a class on a member function without needing to repeat the arguments of the member function -- i e, derive them automatically.
I know how to do this if I name the class based on how many arguments the function takes, but I want to derive that as well.
Something like this, although this doesn't work (at least in MSVC 2008 sp1, which is my target compiler):
class Foo {
void func0();
int func2(char *, float);
};
template<typename T> class Wrapper;
// specialize for zero-argument void func
template<typename Host, void (Host::*Func)()> class Wrapper<Func> : public Base {
... specialization goes here ...
};
// specialize for two-argument value func
template<typename Host, typename Ret, typename Arg0, typename Arg1, Ret (Host::*Func)(Arg0, Arg1)> class Wrapper<Func> : public Base {
... specialization goes here ...
};
Through "Base" I can then treat these polymorphically. In the end, I want to use this to create a simple wrapper syntax for a scripting language:
WrapClass<Bar> wrap(
MemberFunction<&Bar::func0>("func0") +
MemberFunction<&Bar::func2>("func2")
);
However, that doesn't work: the specialization syntax is wrong, because you can't match a function pointer to a typename argument.
I believe you'll need to take a traits approach, the most common library of which is boost's, but if you wanted to avoid boost, it wouldn't be extremely difficult to roll your own if you limited the scope of the implementation to just pointer-to-member-functions and the traits on those you need (modern c++ design is a great book explaining the theory). Here's how I would do it with boost's function_traits and enable_if.
You could use a generic template argument, enable_if it for function pointers, then use function types (or type traits) to pull out out the information you need:
#include <boost/function_types/function_arity.hpp>
#include <boost/function_types/is_member_pointer.hpp>
template<typename T, class Enable = void> class Wrapper;
/* other specializations... */
// For member functions:
template <class T>
class Wrapper<T, typename enable_if<is_member_pointer<T> >::type>
{ /* function_arity<T>::value has the number of arguments */ };
See this and this
The C++ standard library provides mem_fun_ref which sort of works how you want, though it only works for nullary and unary functions. Of course, you can use a struct with all the parameters as your one argument.