using enable_if with template specialization - c++

I want to make function get_type_name. For types that belong to certain set example are numbers, geometry etc I want to make one get_type_name function which uses enable_if with type trait. And for each type that do not belong to particular set I want to specialize its own get_type_name function. This is my code and I get the following compiler error and can't figure out why:
error C2668: 'get_type_name': ambiguous call to overloaded function
could be 'std::string get_type_name(myenable_if::type
*)' or 'std::string get_type_name(void *)'
template<bool B, typename T = void>
struct myenable_if {};
template<typename T>
struct myenable_if<true, T> { typedef void type; };
template<class T>
struct is_number
{
static const bool value = false;
};
template<>
struct is_number<int>
{
static const bool value = true;
};
template<class T>
std::string get_type_name(void* v=0);
//get_type_name for specific type
template<>
std::string get_type_name<std::string>(void*)
{
return std::string("string");
}
//get_type_name for set of types
template<class T>
std::string get_type_name(typename myenable_if<is_number<T>::value>::type* t=0)
{
return std::string("number");
}
int main()
{
std::string n = get_type_name<int>();
}

Here is a working version.
#include <iostream>
#include <string>
#include <vector>
#include <iostream>
template<bool B, typename T = void>
struct myenable_if {};
template<typename T>
struct myenable_if<true, T> { typedef T type; };
template<class T>
struct is_number
{
static const bool value = false;
};
template<>
struct is_number<int>
{
static const bool value = true;
};
template<class T>
std::string get_type_name_helper(void* t, char)
{
return "normal";
}
template<class T>
typename myenable_if<is_number<T>::value, std::string>::type get_type_name_helper(void* t, int)
{
return "number";
}
//get_type_name for specific type
template<>
std::string get_type_name_helper<std::string>(void* t, char)
{
return std::string("string");
}
template <class T>
std::string get_type_name(void* t = 0)
{
return get_type_name_helper<T>(t, 0);
}
int main() {
std::string n = get_type_name<int>();
std::cout << n << '\n';
n = get_type_name<std::string>();
std::cout << n << '\n';
n = get_type_name<float>();
std::cout << n << '\n';
return 0;
}
See Live Demo

Related

Partial template specialization of 2nd parameter

I'm working on a C++11 wrapper around a C api. The C api offers a bunch of getters for various types, with a different name for each type. Values are retrieved by array of a given size, known at compilation.
I want to give the type and the array size by template, to call the right function.
#include <string>
#include <iostream>
template <typename T>
struct make_stop {
constexpr static bool value = false;
};
class Foo
{
public:
Foo() : i(42) {}
template<typename T, size_t n>
T get();
private:
int i = 0;
};
template<typename T, size_t n>
T Foo::get() { static_assert(make_stop<T>::value); return T(); }
template<int, size_t n>
int Foo::get() { return i + n; }
int main() {
Foo foo;
int i = foo.get<int, 4>();
double f = foo.get<double, 2>();
return 0;
}
But it fails to match the right function
main.cpp:26:5: error: no declaration matches 'int Foo::get()'
int Foo::get() { return i + n; }
^~~
main.cpp:15:7: note: candidate is: 'template<class T, long unsigned int n> T Foo::get()'
T get();
its a bit vauge from your question, but assuming you are wanting to index into some c- arrays and return the value at I you can't specialize function templates like you want, but you can use some tags instead, something like..
class Foo
{
public:
Foo() : is{1,2,3,4,5,6,7,8,9,10},ds{1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8,9.9,10.1} {}
template <typename T> struct type_c{};
template <size_t I> struct int_c{};
template<typename T,size_t I>
auto get()
{ return get_impl(type_c<T>(),int_c<I>()); }
private:
template <size_t I>
auto get_impl(type_c<int>,int_c<I>)
{ return is[I]; }
template <size_t I>
auto get_impl(type_c<double>,int_c<I>)
{ return ds[I]; }
int is[10];
double ds[10];
};
int main() {
Foo foo;
int i = foo.get<int,0>();
double d = foo.get<double,2>();
std::cout << i << " " << d << std::endl;
return 0;
}
Demo
If I understood you correctly you want to partially specialize get for T. Unfortunately partial specialization for methods is not allowed by the standard. You can however get around this with a static method on a class templated by T and specializing the class.
Like this:
template <class T> struct Foo_helper;
struct Foo
{
Foo() : i{42} {}
template<class T, std::size_t N>
T get()
{
return Foo_helper<T>::template get<N>(*this);
}
int i = 0;
};
template <class T> struct Foo_helper {};
// specialize Foo_helper for each type T you wish to support:
template <> struct Foo_helper<int>
{
template <std::size_t N>
static int get(const Foo& foo) { return foo.i + N; }
};
template <> struct Foo_helper<double>
{
template <std::size_t N>
static double get(const Foo& foo) { return foo.i + N; }
};
int main()
{
Foo foo{};
int i = foo.get<int, 4>();
double d = foo.get<double, 2>();
}

Check if object is instance of class with template

My class:
template < typename T >
Array<T>{};
(Source data is stored in vector)
I have an object:
Array< string > a;
a.add("test");
And I have an object:
Array< Array< string > > b;
b.add(a);
How can I check:
Is b[0] an instance of Array (regardless of template type)?
Is a[0] an instance of any type except Array?
If you can use C++11, creating your type traits; by example
#include <string>
#include <vector>
#include <iostream>
#include <type_traits>
template <typename T>
struct Array
{
std::vector<T> v;
void add (T const t)
{ v.push_back(t); }
};
template <typename>
struct isArray : public std::false_type
{ };
template <typename T>
struct isArray<Array<T>> : public std::true_type
{ };
template <typename T>
constexpr bool isArrayFunc (T const &)
{ return isArray<T>::value; }
int main()
{
Array<std::string> a;
Array<Array<std::string>> b;
a.add("test");
b.add(a);
std::cout << isArrayFunc(a.v[0]) << std::endl; // print 0
std::cout << isArrayFunc(b.v[0]) << std::endl; // print 1
}
If you can't use C++11 or newer but only C++98, you can simply write isArray as follows
template <typename>
struct isArray
{ static const bool value = false; };
template <typename T>
struct isArray< Array<T> >
{ static const bool value = true; };
and avoid the inclusion of type_traits
--- EDIT ---
Modified (transformed in constexpr) isArrayFunc(), as suggested by Kerrek SB (thanks!).
Below is a shorter version of the solution proposed by max66 that no longer uses struct isArray.
It works in C++98 and later revisions.
#include <string>
#include <vector>
#include <iostream>
template <typename T>
struct Array
{
std::vector<T> v;
void add (T const t)
{ v.push_back(t); }
};
template <typename T>
constexpr bool isArrayFunc (T const &)
{ return false; }
template <typename T>
constexpr bool isArrayFunc (Array<T> const &)
{ return true; }
int main()
{
Array<std::string> a;
Array<Array<std::string>> b;
a.add("test");
b.add(a);
std::cout << isArrayFunc(a.v[0]) << std::endl; // print 0
std::cout << isArrayFunc(b.v[0]) << std::endl; // print 1
}
in c++ you can use
if(typeid(obj1)==typeid(ob2))//or typeid(obj1)==classname
cout <<"obj1 is instance of yourclassname"
in your case you can check that with typeid(obj1)==std::array

Boost fusion sequence type and name identification for structs and class

I am trying to use boost fusion for one of my projects and I an figuring out how to get type names and variable names for structures and classes.
#include <typeinfo>
#include <string>
#include <iostream>
#include <boost/fusion/include/sequence.hpp>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/adapt_adt.hpp>
#include <boost/lexical_cast.hpp>
using namespace boost::fusion;
struct Foo
{
int integer_value;
bool boolean_value;
};
class Bar
{
int integer_value;
bool boolean_value;
public:
Bar(int i_val, bool b_val):integer_value(i_val),boolean_value(b_val) {}
int get_integer_value() const { return integer_value; }
void set_integer_value(int i_val) { integer_value = i_val; }
bool get_boolean_value() const { return boolean_value; }
void set_boolean_value(bool b_val) { boolean_value = b_val; }
};
BOOST_FUSION_ADAPT_STRUCT(
Foo,
(int, integer_value)
(bool, boolean_value)
)
BOOST_FUSION_ADAPT_ADT(
Bar,
(int, int, obj.get_integer_value() , obj.set_integer_value(val))
(bool, bool, obj.get_boolean_value(), obj.set_boolean_value(val))
)
struct DisplayMembers
{
template <typename T>
void operator()(T& t) const {
std::cout << typeid(t).name() << " : " << boost::lexical_cast<std::string>(t) << std::endl;
}
};
int main(int argc, char *argv[])
{
struct Foo f = { 33, false};
for_each(f, DisplayMembers());
Bar b(34,true);
for_each(b, DisplayMembers());
return 0;
}
In the above example the result is
int : 33
bool : 0
struct boost::fusion::extension::adt_attribute_proxy<class Bar,0,0> : 34
struct boost::fusion::extension::adt_attribute_proxy<class Bar,1,0> : 1
I want the result as
int : integer_value : 33
bool : boolean_value : 0
int : integer_value : 34
bool : boolean_value : 1
I distilled the answer by sehe into something much simpler, provided you are using C++14
#include <iostream>
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/mpl/range_c.hpp>
struct MyStruct {
std::string foo;
double bar;
};
BOOST_FUSION_ADAPT_STRUCT(MyStruct,
foo,
bar)
namespace fuz = boost::fusion;
namespace mpl = boost::mpl;
int main(int argc, char* argv[]) {
MyStruct dummy{"yo",3.14};
fuz::for_each(mpl::range_c<
unsigned, 0, fuz::result_of::size<MyStruct>::value>(),
[&](auto index){
std::cout << "Name: "
<< fuz::extension::struct_member_name<MyStruct,index>::call()
<< " Value: "
<< fuz::at_c<index>(dummy) << std::endl;
});
}
Outputs:
Name: foo Value: yo
Name: bar Value: 3.14
See it live on coliru
There's boost::fusion::extension::struct_member_name<S, N::value> to access the names.
Here's a generic fusion object visitor that I use:
namespace visitor {
template <typename Flavour, typename T> struct VisitorApplication;
namespace detail
{
template <typename V, typename Enable = void>
struct is_vector : boost::mpl::false_ { };
template <typename T>
struct is_vector<std::vector<T>, void> : boost::mpl::true_ { };
namespace iteration
{
// Iteration over a sequence
template <typename FusionVisitorConcept, typename S, typename N>
struct members_impl
{
// Type of the current member
typedef typename boost::fusion::result_of::value_at<S, N>::type current_t;
typedef typename boost::mpl::next<N>::type next_t;
typedef boost::fusion::extension::struct_member_name<S, N::value> name_t;
static inline void handle(FusionVisitorConcept& visitor, const S& s)
{
visitor.start_member(name_t::call());
VisitorApplication<FusionVisitorConcept, current_t>::handle(visitor, boost::fusion::at<N>(s));
visitor.finish_member(name_t::call());
members_impl<FusionVisitorConcept, S, next_t>::handle(visitor, s);
}
};
// End condition of sequence iteration
template <typename FusionVisitorConcept, typename S>
struct members_impl<FusionVisitorConcept, S, typename boost::fusion::result_of::size<S>::type>
{
static inline void handle(FusionVisitorConcept const&, const S&) { /*Nothing to do*/ }
};
// Iterate over struct/sequence. Base template
template <typename FusionVisitorConcept, typename S>
struct Struct : members_impl<FusionVisitorConcept, S, boost::mpl::int_<0>> {};
} // iteration
template <typename FusionVisitorConcept, typename T>
struct array_application
{
typedef array_application<FusionVisitorConcept, T> type;
typedef typename T::value_type value_type;
static inline void handle(FusionVisitorConcept& visitor, const T& t)
{
visitor.empty_array();
for (auto& el : t)
VisitorApplication<FusionVisitorConcept, value_type>::handle(visitor, el);
}
};
template <typename FusionVisitorConcept, typename T>
struct struct_application
{
typedef struct_application<FusionVisitorConcept, T> type;
static inline void handle(FusionVisitorConcept& visitor, const T& t)
{
visitor.empty_object();
iteration::Struct<FusionVisitorConcept, T>::handle(visitor, t);
}
};
template <typename FusionVisitorConcept, typename T, typename Enable = void>
struct value_application
{
typedef value_application<FusionVisitorConcept, T> type;
static inline void handle(FusionVisitorConcept& visitor, const T& t) {
visitor.value(t);
}
};
template <typename FusionVisitorConcept, typename T>
struct value_application<FusionVisitorConcept, boost::optional<T> >
{
typedef value_application<FusionVisitorConcept, boost::optional<T> > type;
static inline void handle(FusionVisitorConcept& visitor, const boost::optional<T>& t) {
if (t)
VisitorApplication<FusionVisitorConcept, T>::handle(visitor, *t);
else
; // perhaps some default action?
}
};
template <typename FusionVisitorConcept, typename T>
struct select_application
{
typedef
//typename boost::mpl::eval_if<boost::is_array<T>, boost::mpl::identity<array_application<FusionVisitorConcept, T>>,
typename boost::mpl::eval_if<detail::is_vector<T>, boost::mpl::identity<array_application <FusionVisitorConcept, T>>,
typename boost::mpl::eval_if<boost::fusion::traits::is_sequence<T>, boost::mpl::identity<struct_application<FusionVisitorConcept, T>>,
boost::mpl::identity<value_application<FusionVisitorConcept, T>>
> >::type type;
};
} // detail
template <typename FusionVisitorConcept, typename T>
struct VisitorApplication : public detail::select_application<FusionVisitorConcept, T>::type
{
};
}
template <typename FusionVisitorConcept, typename T>
void apply_fusion_visitor(FusionVisitorConcept& visitor, T const& o)
{
visitor::VisitorApplication<FusionVisitorConcept, T>::handle(visitor, o);
}
You can use it by supplying a visitor, e.g. for xml-like output:
struct DisplayMemberVisitor {
typedef std::string result_type;
DisplayMemberVisitor() { ss << std::boolalpha; }
std::string complete() { return ss.str(); }
void start_member (const char* name) {
ss << "<" << name << ">";
}
void finish_member(const char* name) {
ss << "</" << name << ">";
}
template <typename T> void value(T const& value) {
ss << value;
}
void empty_object() { }
void empty_array() { }
private:
std::stringstream ss;
};
See it Live On Coliru where (including some debug output) it prints:
<integer_value>33</integer_value><boolean_value>false</boolean_value><integer_value>34</integer_value><boolean_value>true</boolean_value>
Note that the ADT adaptation macro doesn't include a name (because none is available). You can probably quite easily make a macro FUSION_ADAPT_KEYD_ADT that also accepts a name and generates the relevant specializations of boost::fusion::extension::struct_member_name.
BONUS MATERIAL
Adding member name traits to ADT adapted members
Here's a simplistic approach that shows what little amount of work needs to be done.
#define MY_ADT_MEMBER_NAME(CLASSNAME, IDX, MEMBERNAME) \
namespace boost { namespace fusion { namespace extension { \
template <> struct struct_member_name<CLASSNAME, IDX> { typedef char const *type; static type call() { return #MEMBERNAME; } \
}; } } }
MY_ADT_MEMBER_NAME(Bar, 0, integer_value)
MY_ADT_MEMBER_NAME(Bar, 1, boolean_value)
This defines a macro to avoid most of the repetition. If you are a BOOST_PP whizkid you could somehow weave this into an adt_ex.hpp¹ header of sorts, so you could instead say:
BOOST_FUSION_ADAPT_ADT(Bar, // NOTE THIS PSEUDO-CODE
(integer_value, int, int, obj.get_integer_value(), obj.set_integer_value(val))
(boolean_value, bool, bool, obj.get_boolean_value(), obj.set_boolean_value(val)))
For now here's the ADT adapted trick Live On Coliru
¹ in case you're interested, here's a tarball of a prepared adt_ex tree (drop in alongsize adt.hpp): adt_ex.tgz as a starting point. It's just adt* but with macros and header guards renamed to adt_ex*

Overriding return type in function template specialization

I would like to specialize a function template such that the return type changes depending on the type of the template argument.
class ReturnTypeSpecialization
{
public:
template<typename T>
T Item();
};
// Normally just return the template type
template<typename T>
T ReturnTypeSpecialization::Item() { ... }
// When a float is specified, return an int
// This doesn't work:
template<float>
int ReturnTypeSpecialization::Item() { ... }
Is this possible? I can't use C++11.
Since the specialization has to agree with the base template on the return type, you can make it so by adding a "return type trait", a struct you can specialize and draw the true return type from:
// in the normal case, just the identity
template<class T>
struct item_return{ typedef T type; };
template<class T>
typename item_return<T>::type item();
template<>
struct item_return<float>{ typedef int type; };
template<>
int item<float>();
Live example.
Note that you might want to stick to the following, so you only need to update the return-type in the item_return specialization.
template<>
item_return<float>::type foo<float>(){ ... }
// note: No `typename` needed, because `float` is not a dependent type
Do all of the specialization in a worker class and use a simple function as a wrapper that will be specialized implicitly.
#include <iostream>
using std::cout;
// worker class -- return a reference to the given value
template< typename V > struct worker
{
typedef V const & type;
static type get( V const & v ) { return v; }
};
// worker class specialization -- convert 'unsigned char' to 'int'
template<> struct worker<unsigned char>
{
typedef int type;
static type get( unsigned char const & v ) { return v; }
};
// mapper function
template< typename V > typename worker<V>::type mapper( V const & v )
{
return worker<V>::get(v);
}
int main()
{
char a='A';
unsigned char b='B';
cout << "a=" << mapper(a) << ", b=" << mapper(b) << "\n";
}
In this example, the specialization of unsigned char causes it to be converted to an int so that cout will display it as a number instead of as a character, generating the following output...
a=A, b=66
Perhaps you could use the following hack. Given these simple type traits:
template<bool b, typename T, typename U>
struct conditional { typedef T type; };
template<typename T, typename U>
struct conditional<false, T, U> { typedef U type; };
template<typename T, typename U>
struct is_same { static const bool value = false; };
template<typename T>
struct is_same<T, T> { static const bool value = true; };
You could write your class and specialized member function as follows:
class ReturnTypeSpecialization
{
public:
template<typename T>
typename conditional<is_same<T, float>::value, int, T>::type
Item();
};
// Normally just return the template type
template<typename T>
typename conditional<is_same<T, float>::value, int, T>::type
ReturnTypeSpecialization::Item() { return T(); }
// When a float is specified, return an int
template<>
int ReturnTypeSpecialization::Item<float>() { return 1.0f; }
Simple test program (uses C++11 just for verification):
int main()
{
ReturnTypeSpecialization obj;
static_assert(std::is_same<decltype(obj.Item<bool>()), bool>::value, "!");
static_assert(std::is_same<decltype(obj.Item<float>()), int>::value, "!");
}
Here is a live example.
You can do template specializations like so:
template<typename T>
T item() {
return T();
}
template<>
float item<float>() {
return 1.0f;
}
Hi I tried to use the template specialization for returning the parameter value for primitives as well as std::string data, while doing so I was getting lot of unresolved external, redefinition kind of errors.
so if any one face something like this, he/she can use something like below when want to return different data types including string,
NOTE: both the Template function must be the part of the Header file (*.h)...
so we are using template specialization string data type here...
inside class as a inline member we have to use template specialize method and in the same file we can define the template as well.
class ConfigFileParser
{
public:
bool ParseConfigFile(const std::string& file_name);
template <typename T>
T GetParameterValue(const std::string key);
template <>
std::string GetParameterValue<std::string>(const std::string key)
{
std::string param_val = "";
//do logical operation here...
return param_val;
}
private:
// private functions...
// private data...
};
template <typename T>
T ConfigFileParser::GetParameterValue(const std::string key)
{
T param_val = 0;
std::stringstream ss;
std::string val_str;
// do some operation here...
ss << val_str.c_str();
ss >> param_val;
return param_val;
}

Problem with SFINAE

Why this code (fnc value in class M) do not get resolved by SFINAE rules? I'm getting an error:
Error 1 error C2039: 'type' : is not a member of
'std::tr1::enable_if<_Test,_Type>'
Of course type is not a member, it isn't defined in this general ver of enable_if but isn't the whole idea behind this to enable this ver of fnc if bool is true and do not instantiate it if it's false? Could please someone explain that to me?
#include <iostream>
#include <type_traits>
using namespace std;
template <class Ex> struct Null;
template <class Ex> struct Throw;
template <template <class> class Policy> struct IsThrow;
template <> struct IsThrow<Null> {
enum {value = 0};
};
template <> struct IsThrow<Throw> {
enum {value = 1};
};
template <template <class> class Derived>
struct PolicyBase {
enum {value = IsThrow<Derived>::value};
};
template<class Ex>
struct Null : PolicyBase<Null> { };
template<class Ex>
struct Throw : PolicyBase<Throw> { } ;
template<template< class> class SomePolicy>
struct M {
//template<class T>
//struct D : SomePolicy<D<T>>
//{
//};
static const int ist = SomePolicy<int>::value;
typename std::enable_if<ist, void>::type value() const
{
cout << "Enabled";
}
typename std::enable_if<!ist, void>::type value() const
{
cout << "Disabled";
}
};
int main()
{
M<Null> m;
m.value();
}
SFINAE does not work for non-template functions. Instead you can e.g. use specialization (of the class) or overload-based dispatching:
template<template< class> class SomePolicy>
struct M
{
static const int ist = SomePolicy<int>::value;
void value() const {
inner_value(std::integral_constant<bool,!!ist>());
}
private:
void inner_value(std::true_type) const { cout << "Enabled"; }
void inner_value(std::false_type) const { cout << "Disabled"; }
};
There is no sfinae here.
After M<Null> is known the variable ist is known also.
Then std::enable_if<ist, void> is well-defined too.
One of your function is not well-defined.
SFINAE works only for the case of template functions.
Where are template functions?
Change your code to
template<int> struct Int2Type {}
void value_help(Int2Type<true> ) const {
cout << "Enabled";
}
void value_help(Int2Type<false> ) const {
cout << "Disabled";
}
void value() const {
return value_help(Int2Type<ist>());
}