Currently, I have some code as follows
template<typename Type>
Type* getValue(std::string name, bool tryUseGetter = true)
{
if(tryUseGetter)
{
if(_properties[name]->hasGetter)
{
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
else
{
return (Type*)_properties[name]->data;
}
}
Is there a way to make tryUseGetter a compile time switch? i.e. move it to the template declaration so it's something akin to this
template<typename Type, bool tryUseGetter = true>
...
Thanks.
As an alternative to Dirk's answer, you can put the function in a struct. Template classes can be partially specialized (in contrast to template functions), so you can write:
template<typename Type, bool tryUseGetter = true>
struct getValue;
template<typename Type>
struct getValue<Type, true>
{
Type* run(std::string name)
{
if(_properties[name]->hasGetter)
{
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
};
template<typename Type>
struct getValue<Type, false>
{
Type* run(std::string name)
{
return (Type*)_properties[name]->data;
}
};
Call it as getValue<T>::run("foo") or getValue<T, false>::run("foo") .
I'm not 100% certain that it's allowed to have template parameters of the type bool, so perhaps you should change it to int.
You can get compile-time dispatch of the "try-use-getter" stuff by splitting your method into two and having the compiler dispatch to the appropriate method:
struct __try_use_getter { }
external const __try_use_getter tryusegetter;
template<typename Type>
Type*
getValue(std::string name, const __try_use_getter&)
{
if(_properties[name]->hasGetter)
{
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
template<typename Type>
Type*
getValue(std::string name)
{
return (Type*)_properties[name]->data;
}
With this scenario in place, you would have full compile-time dispatching:
int result = getValue("foo", tryusegetter);
would try the getter first, whereas
int result = getValue("foo");
would immediately call the getter-less version.
Just in case you really need it (although from a performance point of view, i doubt it would be noticeable), i would overload
template<typename Type>
Type* getValue(std::string const &name)
{
if(_properties[name]->hasGetter)
{
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
template<typename Type, bool tryUseGetter>
Type *getValue(std::string const &name)
{
if(tryUseGetter)
{
return getValue<Type>(name);
}
else
{
return (Type*)_properties[name]->data;
}
}
Also, you should first follow the real rules: Pass name by-const-reference instead of passing a copy, for example.
You could use type cast operator and structure getValue as follows (usage syntax will be the same as with function) :
template<typename Type, bool tryUseGetter = true>
struct getValue {};
template<typename Type>
struct getValue<Type, true> {
getValue(const std::string& name) : name(name) {};
operator Type*() const {
if(_properties[name]->hasGetter) {
return (Type*)_properties[name]->getter();
}
return (Type*)_properties[name]->data;
}
private:
const std::string& name;
};
template<typename Type>
struct getValue<Type, false> {
getValue(const std::string& name) : name(name) {};
operator Type*() const {
return (Type*)_properties[name]->data;
}
private:
const std::string& name;
};
Usage:
int main () {
int* i = getValue<int>( "TEST" ); // true by default
Xstruct* x = getValue<Xstruct, false>( "XS" ); // false
}
Before you go and make the code all complicated...did you check to see if the optimizing compiler was already doing this for you?
Related
I'm pretty new to template concepts like SFINAE or tag dispatching and been reading some articles and examples about it that didn't help me getting to my approach. So I would really appreciate if someone can help please.
My goal is to have 1 single parse function that will do some stuff before passing forward the data to some other functions to do specific parsing depending on the template T type.
In the attached code, this is kind of the behavior I want to have. I use here if constexpr which unfortunately is a C++17 feature that is not available in the C++ version I use.
I think for that purpose it looks like in first look template specialization would be the best solution, but it's not what I wanted.
I think for that purpose tag dispatching would be a good direction, but I'm not sure how exactly to do that with type_traits when I have custom types, as it's always like I have 2 options, a true_type or false_type, but in the following code I have 3 situation with potential of having more.
I would really appreciate for some examples or directions please of what's the best approach to do what I'm looking for. Even some article to read would be great.
Thanks in advance!
Working code example:
#include <string>
#include <vector>
#include <memory>
using namespace std;
struct Base { int id; };
struct Foo : Base { int fooValue; };
struct Bar : Base { int barValue; };
shared_ptr<Foo> parseFoo(const string & data) { return make_shared<Foo>(); }
shared_ptr<Bar> parseBar(const string & data) { return make_shared<Bar>(); }
shared_ptr<vector<Foo>> parseFoos(const string & data) { return make_shared<vector<Foo>>(); }
template <typename T>
shared_ptr<T> parse(const std::string & data)
{
shared_ptr<T> result = nullptr;
if (data.empty())
return result;
result = make_shared<T>();
if constexpr (std::is_same<T, Foo>::value) result = parseFoo(data);
else if constexpr (std::is_same<T, Bar>::value) result = parseBar(data);
else if constexpr (std::is_same<T, vector<Foo>>::value) result = parseFoos(data);
return result;
}
int main()
{
string data = "some json response";
auto foo = parse<Foo>(data);
auto bar = parse<Bar>(data);
auto foos = parse<vector<Foo>>(data);
return 0;
}
Tag dispatching would make it easier here:
struct Base { int id; };
struct Foo : Base { int fooValue; };
struct Bar : Base { int barValue; };
template <typename T> struct Tag {};
std::shared_ptr<Foo> parse_impl(Tag<Foo>, const std::string& data) { return make_shared<Foo>(); }
std::shared_ptr<Bar> parse_impl(Tag<Bar>, const std::string& data) { return make_shared<Bar>(); }
std::shared_ptr<std::vector<Foo>> parse_impl(Tag<std::vector<Foo>>, const std::string& data)
{
return make_shared<std::vector<Foo>>();
}
template <typename T>
std::shared_ptr<T> parse(const std::string& data)
{
if (data.empty())
return nullptr;
return parse_impl(Tag<T>{}, data);
}
Why don't you just provide template specializations for parseFoo, parseBar and parseFoos and then just call the template method from within the static parse function:
//parseT replaces parseFoo, parseBar, parseFoos
template<typename T>
std::shared_ptr<T> parseT(const std::string & data);
// provide implementaiton for Foo, Bar and vector<Foo>
template<>
std::shared_ptr<Foo> parseT<Foo>(const std::string & data) {
return std::make_shared<Foo>();
}
template<>
std::shared_ptr<Bar> parseT<Bar>(const std::string & data) {
return std::make_shared<Bar>();
}
template<>
std::shared_ptr<std::vector<Foo>> parseT<std::vector<Foo>>(const std::string & data) {
return std::make_shared<std::vector<Foo>>();
}
template <typename T>
std::shared_ptr<T> parser(const std::string & data) {
std::shared_ptr<T> result = nullptr;
if (data.empty())
return result;
result = std::make_shared<T>();
result = parseT<T>(data); // simple call to template function
return result;
}
EDIT: Whoops, didn't read properly enough, now I see that's not what you wanted (though not really sure why, it seems to be the best option for me :D). Anyways, if you want to use tag dispatching something along the lines of the following code comes to my mind (again IMO not that nice, due to another template parameter for the parser function):
struct FooTag {};
struct BarTag{};
struct FoosTag{};
std::shared_ptr<Foo> parseT(const std::string & data, FooTag) {
return std::make_shared<Foo>();
}
std::shared_ptr<Bar> parseT(const std::string & data, BarTag) {
return std::make_shared<Bar>();
}
std::shared_ptr<std::vector<Foo>> parseT(const std::string & data, FoosTag) {
return std::make_shared<std::vector<Foo>>();
}
// template version
template <typename T, typename Tag>
std::shared_ptr<T> parser(const std::string & data) {
std::shared_ptr<T> result = nullptr;
if (data.empty())
return result;
result = std::make_shared<T>();
result = parseT(data, Tag());
return result;
}
If you don't want the extra template parameter, you can let the user provide a tag class inside of Foo and Bar and whatsoever, but will not work when you have a vector of Foos:
// Tag is now a nested class
class Foo {
public:
struct Tag{};
};
class Bar {
public:
struct Tag{};
};
std::shared_ptr<Foo> parseT(const std::string & data, Foo::Tag) {
return std::make_shared<Foo>();
}
std::shared_ptr<Bar> parseT(const std::string & data, Bar::Tag) {
return std::make_shared<Bar>();
}
template <typename T>
std::shared_ptr<T> parser(const std::string & data) {
std::shared_ptr<T> result = nullptr;
if (data.empty())
return result;
result = std::make_shared<T>();
result = parseT(data, T::Tag()); // tag is now inside of template parameter
return result;
}
Another EDIT:
You could make a template class for the Tag, in order to get rid of the extra template parameter in the parser function
template <typename T>
struct Tag{};
std::shared_ptr<Foo> parseT(const std::string & data, Tag<Foo>) {
return std::make_shared<Foo>();
}
std::shared_ptr<Bar> parseT(const std::string & data, Tag<Bar>) {
return std::make_shared<Bar>();
}
template <typename T>
std::shared_ptr<T> parser(const std::string & data) {
std::shared_ptr<T> result = nullptr;
if (data.empty())
return result;
result = std::make_shared<T>();
result = parseT(data, Tag<T>{});
return result;
}
Consider the following simplified piece of code for a variant class. Most of it is for informational purposes, the question is about the conditional_invoke method.
// Possible types in variant.
enum class variant_type { empty, int32, string };
// Actual data store.
union variant_data {
std::int32_t val_int32;
std::string val_string;
inline variant_data(void) { /* Leave uninitialised */ }
inline ~variant_data(void) { /* Let variant do clean up. */ }
};
// Type traits which allow inferring which type to use (these are actually generated by a macro).
template<variant_type T> struct variant_type_traits { };
template<class T> struct variant_reverse_traits { };
template<> struct variant_type_traits<variant_type::int32> {
typedef std::int32_t type;
inline static type *get(variant_data& d) { return &d.val_int32; }
};
template<> struct variant_reverse_traits<std::int32_t> {
static const variant_type type = variant_type::int32;
inline static std::int32_t *get(variant_data& d) { return &d.val_int32; }
};
template<> struct variant_type_traits<variant_type::string> {
typedef std::string type;
inline static type *get(variant_data& d) { return &d.val_string; }
};
template<> struct variant_reverse_traits<std::string> {
static const variant_type type = variant_type::string;
inline static std::string *get(variant_data& d) { return &d.val_string; }
};
// The actual variant class.
class variant {
public:
inline variant(void) : type(variant_type::empty) { }
inline ~variant(void) {
this->conditional_invoke<destruct>();
}
template<class T> inline variant(const T value) : type(variant_type::empty) {
this->set<T>(value);
}
template<class T> void set(const T& value) {
this->conditional_invoke<destruct>();
std::cout << "Calling data constructor ..." << std::endl;
::new (variant_reverse_traits<T>::get(this->data)) T(value);
this->type = variant_reverse_traits<T>::type;
}
variant_data data;
variant_type type;
private:
template<variant_type T> struct destruct {
typedef typename variant_type_traits<T>::type type;
static void invoke(type& v) {
std::cout << "Calling data destructor ..." << std::endl;
v.~type();
}
};
template<template<variant_type> class F, class... P>
inline void conditional_invoke(P&&... params) {
this->conditional_invoke0<F, variant_type::int32, variant_type::string, P...>(std::forward<P>(params)...);
}
template<template<variant_type> class F, variant_type T, variant_type... U, class... P>
void conditional_invoke0(P&&... params) {
if (this->type == T) {
F<T>::invoke(*variant_type_traits<T>::get(this->data), std::forward<P>(params)...);
}
this->conditional_invoke0<F, U..., P...>(std::forward<P>(params)...);
}
template<template<variant_type> class F, class... P>
inline void conditional_invoke0(P&&... params) { }
};
The code works this way, i.e. it works as long as the parameter list P... for the functor is empty. If I add another functor like
template<variant_type T> struct print {
typedef typename variant_type_traits<T>::type type;
static void invoke(type& v, std::ostream& stream) {
stream << v;
}
};
and try to invoke it
friend inline std::ostream& operator <<(std::ostream& lhs, variant& rhs) {
rhs.conditional_invoke<print>(lhs);
return lhs;
}
the compiler VS 20115 complains
error C2672: 'variant::conditional_invoke0': no matching overloaded function found
or gcc respectively
error: no matching function for call to 'variant::conditional_invoke0 >&>(std::basic_ostream&)'
I guess the compiler cannot decide when U... ends and when P... starts. Is there any way to work around the issue?
You'll have to make both parameter packs deducible. That is, let the type and non-type template parameters be part of a function parameter list. For that, introduce a dummy structure:
template <variant_type...>
struct variant_type_list {};
and let the compiler deduce the variant_type... pack from a function call:
template <template <variant_type> class F
, variant_type T
, variant_type... U
, typename... P>
void conditional_invoke0(variant_type_list<T, U...> t
, P&&... params)
{
if (this->type == T)
{
F<T>::invoke(*variant_type_traits<T>::get(this->data)
, std::forward<P>(params)...);
}
this->conditional_invoke0<F>(variant_type_list<U...>{}
, std::forward<P>(params)...);
}
To break recursive calls, introduce an overload with an empty variant_type_list:
template <template <variant_type> class F, typename... P>
void conditional_invoke0(variant_type_list<>, P&&... params) {}
When calling the invoker for the first time, provide variant_types as an argument:
this->conditional_invoke0<F>(variant_type_list<variant_type::int32, variant_type::string>{}
, std::forward<P>(params)...);
DEMO
I have a C++ class that might work with linear or binary search.
Currently I have additional member variable that show what search to be used.
I know how I can do the search with Java-like virtual functions (strategy pattern or template method),
but I am curious what is best practice this to be done compile time with templates<>?
Current (simplified) code looks like this:
int MyArray::lookup(const String &key) const{
if (lookupMethod == LINEAR_SEARCH)
return lookupLinearSearch(key);
else
return lookupBinarySearch(key);
}
The most obvious way is to encapsulate the strategies in types and implement lookup() as a function template:
namespace searchStrategy {
struct linearSearch {
static auto lookup(const MyArray& a, const String &key)
-> int {
return a.lookupLinearSearch(key);
};
};
struct binarySearch {
static auto lookup(const MyArray& a, const String &key)
-> int {
return a.lookupBinarySearch(key);
};
};
}
class MyArray {
public:
template <typename LookupStrategy>
auto lookup(const String &key) const
-> int {
return LookupStrategy::lookup(*this, key);
};
};
// ...
auto myArray = MyArray{};
mArray.lookup<searchStrategy::binarySearch>("asdf"s);
Alternatively you can specialize the template and use the strategy type as tag only:
namespace searchStrategy {
struct linearSearch {};
struct binarySearch {};
}
class MyArray {
public:
template <typename LookupStrategy>
int lookup(const String &key) const;
template <>
int lookup<searchStrategy::linearSearch>(const String &key) const {
return lookupLinearSearch(key);
};
template <>
int lookup<searchStrategy::binarySearch>(const String &key) const {
return lookupBinarySearch(key)
};
};
// ...
auto myArray = MyArray{};
mArray.lookup<searchStrategy::binarySearch>("asdf"s);
Now you might prefer to not have to define the template parameters, but use a function parameter instead. You don't even need templates for that, but just method overloading:
namespace searchStrategy {
struct LinearSearchT {};
struct BinarySearchT {};
static const LinearSearchT linearSearch;
static const BinarySearchT binarySearch;
}
class MyArray {
public:
int lookup(const String &key,
const searchStrategy::linearSearchT strategy) const {
return lookupLinearSearch(key);
};
int lookup(const String &key,
const searchStrategy::binarySearchT strategy) const {
return lookupBinarySearch(key)
};
};
// ...
auto myArray = MyArray{};
mArray.lookup("asdf"s, searchStrategy::binarySearch);
Looks like dynamically choosing the strategy, but is static. You can not do something like this:
mArray.lookup("asdf"s, (someReason) ?
searchStrategy::binarySearch :
searchStrategy::linearSearch);
In that case you'd have to write
if( someReason )
mArray.lookup("asdf"s, searchStrategy::binarySearch);
else
mArray.lookup("asdf"s, searchStrategy::linearSearch);
Beware: all code in this answer is untested. It will contain bugs.
You can use template specialization, provided lookupMethod is known at compile time.
For example, you can do it like this:
template <int METHOD>
int MyArray::lookup(const String& key); // Not implemented
template<>
int MyArray::lookup<LINEAR_SEARCH>(const String& key) {
return lookupLinearSearch(key);
}
template<>
int MyArray::lookup<BINARY_SEARCH>(const String& key) {
return lookupBinarySearch(key);
}
If you are willing to always commit to which strategy you are going to use at compile time, you can do this:
enum class METHOD {LINEAR_SEARCH, BINARY_SEARCH};
template <METHOD M>
int MyArray::lookup(const String & key) {
if (M == METHOD::LINEAR_SEARCH)
return lookupLinearSearch(key);
else
return lookupBinarySearch(key);
}
I'm new in using templates in C++, I want to do different things depending on type used between < and >, so function<int>() and function<char>() won't do the same things.
How can I achieve this?
template<typename T> T* function()
{
if(/*T is int*/)
{
//...
}
if(/*T is char*/)
{
//...
}
return 0;
}
You want to use explicit specialization of your function template:
template<class T> T* function() {
};
template<> int* function<int>() {
// your int* function code here
};
template<> char* function<char>() {
// your char* function code here
};
Create template specializations:
template<typename T> T* function()
{
//general case general code
}
template<> int* function<int>()
{
//specialization for int case.
}
template<> char* function<char>()
{
//specialization for char case.
}
Best practices involves tag dispatch, because specialization is tricky.
Tag dispatch is easier to use quite often:
template<typename T>
T* only_if_int( std::true_type is_int )
{
// code for T is int.
// pass other variables that need to be changed/read above
}
T* only_if_int( std::false_type ) {return nullptr;}
template<typename T>
T* only_if_char( std::true_type is_char )
{
// code for T is char.
// pass other variables that need to be changed/read above
}
T* only_if_char( std::false_type ) {return nullptr;}
template<typename T> T* function()
{
T* retval = only_if_int( std::is_same<T, int>() );
if (retval) return retval;
retval = only_if_char( std::is_same<T, char>() );
return retval;
}
template<class T>
T Add(T n1, T n2)
{
T result;
result = n1 + n2;
return result;
}
For In detail understanding of template, go through the below link:
http://www.codeproject.com/Articles/257589/An-Idiots-Guide-to-Cplusplus-Templates-Part-1
you can define overloaded functions something like this:
#define INTT 0
#define CHARR 1
template<typename T>
T* function()
{
int type;
type = findtype(T);
//do remaining things based on the return type
}
int findType(int a)
{
return INTT;
}
int findType(char a)
{
return CHARR;
}
Given the following declaration:
template<class T>
class A {
void run(T val) {
val.member ...
}
}
This code works fine if no pointers are used:
A<Type> a;
Type t;
a.run(t);
But using a pointer results in an error:
A<Type*> a;
Type* t = new Type();
a.run(t);
error: request for member ‘member’ which is of non-class type ‘T*’
Obviously in this case the member must be accessed via ->. What's the best way to handle this?
I found a solution on SO: Determine if Type is a pointer in a template function
template<typename T>
struct is_pointer { static const bool value = false; };
template<typename T>
struct is_pointer<T*> { static const bool value = true; };
...
if (is_pointer<T>::value) val->member
else val.member
But this is very verbose. Any better ideas?
You could use a simple pair of overloaded function templates:
template<typename T>
T& access(T& t) { return t; }
template<typename T>
T& access(T* t) { return *t; }
And then use them this way:
access(val).member = 42;
For instance:
template<typename T>
struct A
{
void do_it(T& val)
{
access(val).member = 42;
}
};
struct Type
{
int member = 0;
};
#include <iostream>
int main()
{
A<Type> a;
Type t;
a.do_it(t);
std::cout << t.member << std::endl;
A<Type*> a2;
Type* t2 = new Type(); // OK, I don't like this, but just to show
// it does what you want it to do...
a2.do_it(t2);
std::cout << t2->member;
delete t2; // ...but then, don't forget to clean up!
}
Here is a live example.
The best idea is probably to specialize your class for pointer types.
template<class T>
class A{ ...};
template<>
class A<T*> { //implement for pointers
};
If you feel that this is too verbose, you can use overload a get_ref function:
template<class T> T& get_ref(T & r) {return r;}
template<class T> T& get_ref(T* r) {return *r;}
template<class T>
class A {
void do(T val) {
get_ref(val).member ...
}
}