I'm trying to do a templated class that runs a function only in certain cases. This is my code:
#include "stdafx.h"
#include <string>
#include <iostream>
template <class T, class U>
struct Typelist
{
typedef T Head;
typedef U Tail;
};
class NullType
{
};
typedef Typelist<int, Typelist<float, Typelist<char*, NullType> > > UsableTypes1;
typedef Typelist<short, Typelist<std::string, NullType> > UsableTypes2;
template <class T>
class MyClass
{
public:
MyClass();
private:
Typelist _types;
};
template<class T>
MyClass<T>::MyClass()
{
_types = T;
}
template<class T>
void MyClass<T>::print(T type)
{
}
MyClass<UsableTypes1> any;
I need to make the code compiler or not only if the variable I pass to the print() function is a type that is in one of the usable types. I know that probably I'll have to use std::enable_if to allow the code to compile or not if print is called with an incorrect type and std::is_same to check the types but I don't know how to combine that functions with a templated class.
This is a test class to help to explain what I want to achieve:
MyClass<UsableTypes1> one;
void TestMyClass()
{
int int_val = 0;
float flt_val = 0.1f;
const char* char_val = "Hi";
short short_val = 10;
std::string str_val = "Hello";
one.print(int_val); // OK
one.print(flt_val); // OK
one.print(char_val); // OK
// one.print( short_val); // compile error
// one.print( str_val ); // compile error
}
Specially I don't know how can I add to print() a non-T-type parameter.
I hope you can help me!
Thank you in advance.
I don't know if you have a good reason for using recursive Typelists to contain your list of types. A more straight forward way would be to make Typelist a variadic template.
Then we can add a constexpr function that returns true if a given type is part of the Typelist.
std::disjunction requires c++17, but something equivalent can be written for c++11 with a recursive template. That will however be more verbose.
#include <iostream>
#include <type_traits>
struct NullType {};
template <typename T, typename U>
struct Typelist {
using Head = T;
using Tail = U;
template <typename Type>
static constexpr bool IsUsable() {
return std::is_same<Type, T>::value;
}
};
template <typename T, typename... U>
struct Typelist<T, Typelist<U...>> {
using Head = T;
using Tail = Typelist<U...>;
template <typename Type>
static constexpr bool IsUsable() {
return std::is_same<Type, T>::value || Typelist<U...>::template IsUsable<Type>();
}
};
using UsableTypes1 = Typelist<int, Typelist<float, Typelist<const char*, NullType>>>;
template <class T>
class MyClass
{
public:
template <typename U>
void print(U u) {
static_assert(T::template IsUsable<U>(), "That is not a usable type");
std::cout << u << std::endl;
}
};
MyClass<UsableTypes1> one;
int main()
{
int int_val = 0;
float flt_val = 0.1f;
const char* char_val = "Hi";
short short_val = 10;
std::string str_val = "Hello";
one.print(int_val); // OK
one.print(flt_val); // OK
one.print(char_val); // OK
// one.print( short_val); // compile error
// one.print( str_val ); // compile error
}
Related
I use std::experimental::is_detected to determine if class has certain member functions:
#include <utility>
#include <experimental/type_traits>
template<typename USC>
class Descriptor
{
private:
template<class T>
using has_member1_t =
decltype(std::declval<T>().member1(std::declval<std::vector<char> &>()));
public:
static constexpr bool has_member1 =
std::experimental::is_detected_convertible_v<long long,
has_member1_t,
USC>;
};
The problem is I also need to determine if class has certain template member function with following signature:
template<typename Derived>
int member2(Eigen::ArrayBase<Derived> &&)
I've tried to do it like so:
//Inside Descriptor
template<class T, class U>
using has_member2_t =
decltype(std::declval<T>().member2(std::declval<Eigen::ArrayBase<U> &&>()));
static constexpr bool has_member2 =
std::experimental::is_detected_convertible_v<long long,
has_member2_t,
USC>;
but it doesn't work. As I'm not really experienced with C++ TMP I would like to know is there a way to achieve this with std::experimental::is_detected or some other utility?
If c++20 is an option, this kind of code has been made a lot easier to both read and write by using concepts.
#include <iostream>
#include <vector>
struct Foo {
int member1(int) {
return 1;
}
template <typename T>
double member2(std::vector<T>) {
return 2.5;
}
};
struct Bar {};
template <typename T>
concept MyConcept = requires (T t) {
{ t.member1(0) } -> std::same_as<int>; // We can check return type
{ t.template member2<int>(std::vector<int>{}) }; // but we don't have to
};
int main() {
static_assert(MyConcept<Foo>);
static_assert(!MyConcept<Bar>);
}
The issue with your attempt is that you are not passing anything as U for the check. I would also modify it to use the .template member2<...> syntax to explicitly check for a template.
Here is an example of that.
#include <iostream>
#include <vector>
#include <utility>
#include <experimental/type_traits>
struct Foo {
int member1(int) {
return 1;
}
template <typename T>
double member2(std::vector<T>) {
return 2.5;
}
};
struct Bar {};
template<class T, class U>
using has_member2_t =
decltype(std::declval<T>().template member2<U>(std::declval<std::vector<U> &&>()));
int main() {
static constexpr bool has_member2_Foo =
std::experimental::is_detected_convertible_v<long long,
has_member2_t,
Foo, double>;
static constexpr bool has_member2_Bar =
std::experimental::is_detected_convertible_v<long long,
has_member2_t,
Bar, double>;
static_assert(has_member2_Foo);
static_assert(!has_member2_Bar);
}
Question to C++ template gurus:
I have created two template "policies" (not sure if this is the right term), which implement storage of some value types in a vector of either dumb or smart pointers:
#include <algorithm>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
template <typename T>
class DumbPtrVec
{
std::vector<T*> m_vec;
public:
using handle = size_t;
~DumbPtrVec() {
std::for_each(begin(m_vec), end(m_vec), [](T* p){ delete p; });
}
handle AddElement(T* p) {
const handle index = m_vec.size();
m_vec.push_back(p);
return index;
}
T* GetElement(const handle& i) {
T* p = (i < m_vec.size())? m_vec[i] : nullptr;
return p;
}
};
template <typename T>
class SmartPtrVec
{
std::vector<std::shared_ptr<T>> m_vec;
public:
using handle = std::weak_ptr<T>;
handle AddElement(T* p) {
m_vec.emplace_back(p);
return m_vec.back(); // gets converted to weak_ptr
}
T* GetElement(const handle& i) {
T* p = (i.expired())? nullptr : i.lock().get();
return p;
}
};
template <typename T, template<typename> typename STORAGE>
class Storage
{
STORAGE<T> m_values;
public:
using handle = typename STORAGE<int>::handle;
handle AddValue(T* v) { return m_values.AddElement(v); }
T* GetValue(handle h) { return m_values.GetElement(h); }
};
int main()
{
constexpr int N = 13;
Storage<int, DumbPtrVec> d;
auto dh = d.AddValue(new int(N));
std::cout << *d.GetValue(dh) << " == " << N <<std::endl;
Storage<int, SmartPtrVec> s;
auto sh = s.AddValue(new int(N));
std::cout << *s.GetValue(sh) << " == " << N << std::endl;
return 0;
}
Everything works fine, so far.
Then I added a template wrapper, that replaces the element "handle" with a unique string and keeps a look-up table for converting strings back to the handles. If this class is explicitly derived from either DumbPtrVec or SmartPtrVec class, everything works, e.g. for SmartPtrVec:
template <typename T>
class StringHandleWrapper : SmartPtrVec<T>
{
using super = typename SmartPtrVec<T>;
using Str2HandleMap = std::unordered_map<std::string, typename super::handle>;
Str2HandleMap m_Name2HandleMap;
public:
using handle = std::string;
handle AddElement(T* p) {
typename super::handle elem = super::AddElement(p);
static int counter = 0;
std::string uuid = std::to_string(++counter);
m_Name2HandleMap[uuid] = elem;
return uuid;
}
T* GetElement(const handle& uuid) {
auto it = m_Name2HandleMap.find(uuid);
return (it != m_Name2HandleMap.end())? super::GetElement(it->second) : nullptr;
}
};
and successful invocation:
Storage<int, StringHandleWrapper> s;
std::string handle = s.AddValue(new int(N));
But I can't figure out how to add a second template parameter, STORAGE, to StringHandleWrapper, so that it could wrap any of DumbPtrVec or SmartPtrVec...
If I change StringHandleWrapper to:
template <typename T, template<typename> typename STORAGE>
class StringHandleWrapper : STORAGE<T>
{
using super = typename STORAGE<T>;
//... rest unchanged
then I can't figure out how to instantiate Storage class, as compiler complains about "too few template arguments":
Storage<int, StringHandleWrapper<SmartPtrVec>> s;
I hope I'm missing something simple...
Thank you for taking your time to look through my long question!
Create another level of template for partial argument application:
template <template <typename, template<typename> typename> class W,
template <typename> typename S>
struct Apply
{
template <typename T> using type = W<T, S>;
};
Then instantiate Storage like this:
Storage<int, Apply<StringHandleWrapper, SmartPtrVec>::type> s;
Just found the answer (it was indeed simple):
I needed to introduce two single-parameter templates
template<typename T> using StringDumbHandleWrapper = StringHandleWrapper<T, DumbPtrVec>;
template<typename T> using StringSmartHandleWrapper = StringHandleWrapper<T, SmartPtrVec>;
and use the new names in Storage instantiation, e.g.
Storage<int, StringDumbHandleWrapper> s;
So much for the long question... :)
I'm new to template-meta-programming and trying to do the first steps with help of Nicolas Brailovsky's blog.
I created the following scenario:
TEST(Check_NthInstance)
{
typedef Lst< char, Lst< int>> a; // a list of types
Instances<a> inst; //Holds an instance value for each type
char& ref1 = NthInstance<a, 0>::get(inst);
ref1 = 'x'; //can easily manipulate an instance depending on the type
int& ref2 = NthInstance<a, 1>::get(inst); //here we get a compile error
}
In the scenario, I'm trying to get a reference to the instance value in
Instances<a> inst;
by index.
The needed declarations are here:
struct NIL
{
typedef NIL Head;
typedef NIL Tail;
};
template <typename H, typename T=NIL> struct Lst
{
typedef H Head;
typedef T Tail;
};
template <typename LST> struct Instances
{
typedef typename LST::Head Elm;
Elm instance;
Instances<typename LST::Tail> next;
};
template <> struct Instances<NIL> {};
template <typename TypeLst, int N> struct NthInstance
{
typedef typename TypeLst::Tail TypeNext;
typedef typename NthInstance<TypeLst, N-1>::NthInstanceType NthInstanceType;
template <typename InstancesLst>
static NthInstanceType& get(InstancesLst &instances_lst)
{
return NthInstance::get(instances_lst.next);
}
};
template <typename TypeLst> struct NthInstance<TypeLst, 0>
{
typedef typename TypeLst::Head NthInstanceType;
template <typename InstancesLst>
static NthInstanceType& get(InstancesLst &instances_lst)
{
return instances_lst.instance;
}
};
I suppose, the problem is the recursive deduction in this line:
return NthInstance::get(instances_lst.next);
Compiler message (VS2010) doesn't really help:
1>...\empty.cpp(59): error C2440: 'initializing' : cannot convert from 'char' to 'int &'
I also found out, that my type dereferencing is not working as expected:
NthInstance<a,0>::NthInstanceType
Should differ from
NthInstance<a,1>::NthInstanceType
The question is, how to write it correctly?
Please provide a non c++11 example, if possible.
You probably wanted to do something like this:
#include <iostream>
struct Nil { };
template <class Type, class Next = Nil>
struct Lst {
typedef Type ValueType;
typedef Next NextType;
Type value;
Next next;
};
template <int N, class L>
struct GetterType:GetterType<N-1, typename L::NextType> { };
template <class L>
struct GetterType<0, L> {
typedef typename L::ValueType ValueType;
};
template <int I>
struct Getter {
template <class L>
static typename GetterType<I, L>::ValueType& get(L &lst) {
return Getter<I-1>::get(lst.next);
}
};
template <>
struct Getter<0> {
template <class L>
static typename GetterType<0, L>::ValueType& get(L &lst) {
return lst.value;
}
};
int main() {
Lst<char, Lst<int> > lst;
Getter<1>::get(lst) = 10;
Getter<0>::get(lst) = 'a';
std::cout << Getter<0>::get(lst) << std::endl;
std::cout << Getter<1>::get(lst) << std::endl;
}
Are you sure this line is correct?
typedef Lst< char, Lst< int>> a; // a list of types
in pre-C++11 it should be
typedef Lst<char, Lst<int> > a; // a list of types
I want to be able to create a generic nested template such that I can find the total size of all classes. To start, imagine for classes A, B, C, etc... each of which have a mSize member, and GetSize() function. I do the following process:
int main()
{
using Abc = A<B<C<>>>; // Imagine it is defined similarly to this for now.
Abc abc;
std::cout << abc.GetSize() << std::endl;
// For abc.GetSize(), this will do the following:
// 1. Go into A::GetSize().
// 2. This will return A::mSize + B::GetSize()
// 3. This will go into B::GetSize()
// 4. This will return B::mSize + C::GetSize()
// 5. Etc
// Overall, we will have the total size of A+B+C as
// A::mSize + B::mSize + C::mSize.
return 0;
}
It will recursively go through each template class until the end and call GetSize(). My current attempts to do so have been using template-templates and variadic templates.
template <template<typename> class First, template<typename> class ...Args>
class A
{
public:
int GetSize() const
{
First<Args...> foo;
return mSize + foo.GetSize();
}
private:
int mSize{1};
};
template <template<typename> class First, template<typename> class ...Args>
class B
{
public:
int GetSize() const
{
First<Args...> foo;
return mSize + foo.GetSize();
}
private:
int mSize{2};
};
template <template<typename> class First, template<typename> class ...Args>
class C
{
public:
int GetSize() const
{
First<Args...> foo;
return mSize + foo.GetSize();
}
private:
int mSize{3};
};
This obviously has not worked. I would really like to be able to achieve the process described in int main().
Notes:
These classes don't necessarily have to be included, or be in order. We could have A<C> or B<E<C<F<>>>>. Ideally, it can be infinitely long.
I don't want to use polymorphism, wanting it to be resolved at runtime. I could have them all inherit from the same class, create a std::vector<Parent*>, push_back each child class, and iterate through using GetSize(). It would be nice to be able to define unique types such as A<B<>>, A<B<C<>>>, etc.
Since your mSize is the same for all instance, your method should be static, and since it looks like it is a constant, it should be a constexpr.
Here is an implementation that uses a general template and then partially instantiate it with specific sizes:
template <int Size, typename T>
struct Holder {
static constexpr int GetSize() {
return Size + T::GetSize();
}
};
template <int Size>
struct Holder<Size, void> {
static constexpr int GetSize() {
return Size;
}
};
template <typename T = void>
using A = Holder<1, T>;
template <typename T = void>
using B = Holder<2, T>;
template <typename T = void>
using C = Holder<3, T>;
Then you can test:
using AB = A<B<>>;
using ABC = A<B<C<>>>;
static_assert(AB::GetSize() == 1 + 2, "Oops!");
static_assert(ABC::GetSize() == 1 + 2 + 3, "Oops!");
Of course you can make A, B, C, ... extends Holder instead of partially instantiate it if you need it.
You could do something like:
#include <iostream>
#include <type_traits>
using namespace std;
template <class T>
struct A {
static constexpr int size = 1;
using inner_type = T;
};
template <class T>
struct B {
static constexpr int size = 2;
using inner_type = T;
};
//template <class T>
struct C {
static constexpr int size = 3;
using inner_type = void;
};
template <class T, class = void>
struct TotalSizeGetter {
static constexpr int get() {
return T::size + TotalSizeGetter<typename T::inner_type>::get();
}
};
template <class T>
struct TotalSizeGetter<T, typename enable_if<is_void<typename T::inner_type>::value>::type> {
static constexpr int get() {
return T::size;
}
};
int main() {
cout << TotalSizeGetter<A<B<C>>>::get() << endl;
}
This uses c++11 constexpr and enable_if but I see this is not a limitation as you use term variadic templates in your question...
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;
}