Is there a way to do this using templated functions in c++ - c++

I'm currently writing some code to convert java code to c++ code and consequently ending up with some pretty hairy issues. My question is, is it possible to have an overloaded operator that returns the templated value from the containing class?
Ie: I want to be able to do the following with the following classes.
SmartPointer<ArrayClass<bool>*> boolArray = new ArrayClass<bool>(true, true, false, false);
bool b = boolArray[1];
template <typename T> class SmartPointer
{
T data;
template <typename U>
U operator [](int i) const
{
return ((*T)(*data))[index];
}
}
template ArrayClass<U>
{
// Various constructors...
U operator [](int i) const
{
// Implementation here
}
}
The problem I get (understandably) is:
error C2783: 'U SmartPointer::operator const' : could not deduce template argument for 'U'
The compiler doesn't know what U is and I want to be able to tell it that it's bool - because this is what the ArrayClass will be returning. The SmartPointer might not contain an array, in which case the [] operator wouldn't make sense. However I want to be able to pass it through to the object inside the smart pointer in case it does... ?
I don't know what to do to make this work. Perhaps it's not possible??
ANSWER:
Thanks to everyone for responding. There are 3 solutions provided that are essentially the same, but I've award this to Oktalist as he got in first.
I still have a difficulty with this solution though, as I'm passing pointers into my SmartPointer class to allow me to use forward declared classes. This prevented me from using T::value_type as my return type, but that appears to be the right way to do it. It looks like I'm asking to much of the compiler and it looks like I'll have to revert back to simply dereferencing the smartpointer in order to do the array access!

The traditional C++03 way is to use a typedef, typically named value_type. In C++11 we can improve upon this with auto and decltype. Here is your example modified to use both:
SmartPointerCPP03<ArrayClass<bool>> boolArray = new ArrayClass<bool>(true, true, false, false);
SmartPointerCPP11<ArrayClass<bool>> boolArray = new ArrayClass<bool>(true, true, false, false);
bool b = boolArray[1];
template <typename T> class SmartPointerCPP03
{
T* data;
typename T::value_type operator [](int i) const
{
return (*data)[i];
}
}
template <typename T> class SmartPointerCPP11
{
T* data;
auto operator [](int i) const -> decltype(std::declval<T>()[i])
{
return (*data)[i];
}
}
template <typename T> class SmartPointerCPP14
{
T* data;
auto operator [](int i) const
{
return (*data)[i];
}
}
template <typename U> ArrayClass
{
// Various constructors...
typedef U value_type;
U operator [](int i) const
{
// Implementation here
}
}
I also took the liberty of changing T data to T* data and removing the * from the parameter in the instantiation. By the way, your (T*) cast was wrong, and I removed that too.

To start with, make the SmartPointer accept the non-pointer type:
SmartPointer<ArrayClass<bool> > boolArray = new ArrayClass<bool>(true, true, false, false);
Add a typedef to the ArrayClass:
template <typename U> class ArrayClass
{
typedef U value_type;
...
};
Then write a metafunction to get the type:
template <typename T> struct ValueTypeOf {
typedef typename T::value_type type;
};
Then use this in the SmartPointer:
template <typename T>
class SmartPointer
{
typedef typename ValueTypeOf<T>::type value_type;
T* data;
value_type operator [](int i) const
{
return ((*data))[index];
}
};
By using the ValueTypeOf metafunction, you can specialize it based upon the type, so if your type does not have a value_type member, you can do something different to get at it.
Edit: to specialize for a pointer type example:
struct A {
typedef int value_type;
};
template <typename T>
struct ValueTypeOf
{
typedef typename T::value_type type;
};
template <typename T>
struct ValueTypeOf<T*>
{
typedef typename T::value_type type;
};
int main()
{
ValueTypeOf<A>::type foo = 0; // foo is an int
ValueTypeOf<A*>::type bar = 0; // bar is an int
return 0;
}

It's been a while, but I used to do a lot of this. Something like the following should work:
Define a typedef in ArrayClass called value_type, and typedef U to that. Then use T::value_type as the return type of operator [] in SmartPointer.

Related

Declare a template pointer without knowing the type

I have this code with a template function. The function can accept any object that is inherited from Object or with an operator providing a pointer to an Object instance. Inside the function I need to get the Object pointer, but it is a template type and I can't figure out the way how to specify the template type.
here is the code:
class IObject
{
};
template<class T>
class Object: public IObject
{
typedef T value_type;
public:
void test()
{
}
operator Object<T>*()
{
return this;
}
};
template<class T>
class Wrapper
{
typedef T value_type;
public:
T object;
operator T*()
{
return &object;
}
};
template<class T>
class Container
{
public:
void func()
{
data.resize(1);
typename T::value_type& ref = data[0];
//IObject* object = ref; //works
Object<?>* object = ref; // How can I specify the template type here?
object->test();
};
T data;
};
int main()
{
Container<std::vector<Object<float>>> container1;
container1.func();
Container<std::vector<Wrapper<Object<int>>>> container2;
container2.func();
return 0;
}
I tried playing with value_type, but as there are technically 2 types of objects can be used as an input, it doesn't work. Also I tried adding extra argument to the function template, but the argument type can't be deduced by the compiler.
First off, either your Wrapper is wrong or your usage of it is wrong. You instantiate Wrapper<Object<int>> but in the class you have:
Object<T> object;
operator Object<T>*()
which is instantiated as
Object<Object<int>> object;
operator Object<Object<int>>*()
You should either instantiate Wrapper<int>, which would "wrap" a Object<int>, or change your class to have this instead:
T object;
operator T*()
but then the typedef T value_type is wrong.
In any case, you can create a type trait to "unwrap" the type:
template<class T>
struct UnwrapT {
using type = T;
};
template<class T>
struct UnwrapT<Wrapper<T>> {
using type = Object<T>;
};
template<class T>
using Unwrap = typename UnwrapT<T>::type;
You can then use this in func:
Unwrap<typename T::value_type>* object = ref;
Demo

How to write a size() function that works on any type of collection objects?

I require a simple way to obtain the count / length / size of an object of class T where T is some sort of collection type, such as a std::map, std::list, std::vector, CStringArray, CString, std::string, …
For most of the standard types, T::size() is the correct answer, for most of the MFC classes T::GetSize() is correct and for CString, it is T::GetLength().
I want to have a like:
template <typename T> auto size(const T & t)
...which evaluates to the correct member function call.
It seems like there should be a simple way to invoke a traits template on T which has a size(const T & t) member, which itself uses SFINAE to exist or not exist, and if it exists, then it is by definition calling an appropriate t.size_function() to return the count of elements in that instance of a T.
I could write an elaborate has_member type-trait template - there are a few examples on stackoverflow - all of them quite convoluted for what seems to me "there must be a simpler approach". With C++ 17, it seems like this issue should be easily and elegantly solved?
These discussions here and here seems to use an inelegant solution with some of the answers using preprocessor macros to get the job done. Is that still necessary?
But... surely, there must be a way to use the fact that calling the correct member function on a T is compilable, and calling the wrong one fails to compile - can't that be used directly to create the correct type traits wrapper for a given type T?
I would like something along the lines of:
template <typename T>
auto size(const T & collection)
{
return collection_traits<T>::count(collection);
}
Where the exact specialization of collection_traits<T> is selected because it is the only one that fits for T (i.e. it calls the correct instance method).
You can use expression SFINAE and multiple overloads.
The idea is as follows: check if x.size() is a valid expression for your type - if it is, invoke and return it. Repeat for .getSize and .getLength.
Given:
struct A { int size() const { return 42; } };
struct B { int getSize() const { return 42; } };
struct C { int GetLength() const { return 42; } };
You can provide:
template <typename T>
auto size(const T& x) -> decltype(x.size()) { return x.size(); }
template <typename T>
auto size(const T& x) -> decltype(x.getSize()) { return x.getSize(); }
template <typename T>
auto size(const T& x) -> decltype(x.GetLength()) { return x.GetLength(); }
Usage:
int main()
{
size(A{});
size(B{});
size(C{});
}
live example on wandbox.org
This solution is easy to extend and seamlessly works with containers that are templatized.
What if a type exposes two getters?
The solution above would result in ambiguity, but it's easy to fix by introducing a ranking/ordering that solves that.
Firstly, we can create a rank class that allows us to arbitrarily prioritize overloads:
template <int N> struct rank : rank<N - 1> { };
template <> struct rank<0> { };
rank<N> is implicitly convertible to rank<N - 1>. An exact match is better than a chain of conversions during overload resolution.
Then we can create a hierarchy of size_impl overloads:
template <typename T>
auto size_impl(const T& x, rank<2>)
-> decltype(x.size()) { return x.size(); }
template <typename T>
auto size_impl(const T& x, rank<1>)
-> decltype(x.getSize()) { return x.getSize(); }
template <typename T>
auto size_impl(const T& x, rank<0>)
-> decltype(x.GetLength()) { return x.GetLength(); }
Finally we provide an interface function that begins the dispatch to the right size_impl overload:
template <typename T>
auto size(const T& x) -> decltype(size_impl(x, rank<2>{}))
{
return size_impl(x, rank<2>{});
}
Using a type like D below
struct D
{
int size() const { return 42; }
int getSize() const { return 42; }
int GetLength() const { return 42; }
};
will now choose the rank<2> overload of size_impl:
live example on wandbox
The simplest solution, IMO, is function overloading.
// Default implementation for std containers.
template <typename Container>
std::size_t size(Container const& c) { return c.size(); }
// Overloads for others.
std::size_t size(CStringArray const& c) { return c.GetSize(); }
std::size_t size(CString const& c) { return c.GetLength(); }
// ... etc.
You need expression SFINAE, and you must play nice with other types which might decide to conform to both interfaces, so study std::size().
The goal is to augment std::size() to work on all types which follow at least one of the conventions, as long as they don't mess up trying to follow any of them.
#include <type_traits>
#include <iterator>
namespace internal {
// Avoid conflict with std::size()
template <class C>
auto size_impl(const C& c, int) -> decltype((void)c.size());
// Avoid conflict with std::size()
template <class T, std::size_t N>
void size_impl(const T (&array)[N], int);
template <class C>
constexpr auto size_impl(const C& c, long)
noexcept(noexcept(c.GetLength()))
-> decltype(c.GetLength())
{ return c.GetLength(); }
template <class C>
constexpr auto size_impl(const C& c, long long)
noexcept(noexcept(c.getSize()))
-> decltype(c.getSize())
{ return c.getSize(); }
};
template <class T>
using enable_if_not_void_t = std::enable_if_t<!std::is_void<T>(), T>;
using std::size;
template <class C>
constexpr auto size(const C& c)
noexcept(noexcept(internal::size_impl(c, 0)))
-> enable_if_not_void_t<decltype(internal::size_impl(c, 0))>
{ return internal::size_impl(c, 0); }
You can get arbitrary levels of precedence for extending things using templates and inheritance:
template <std::size_t N>
struct priority : priority<N - 1> {};
template <>
struct priority<0> {};
Something like the proposed Abbreviated Lambdas for Fun and Profit would greatly simplify things.

c++ Templates to change constness of a function

I am interested in designing a template interface where the const ness of the function and return type itself changes depending on the template parameter. I have managed to do this for the return type as follows.
template<typename T, bool canChange>
struct Changable{};
template<typename T>
struct Changable<T,true>
{
typedef T type;
};
template<typename T>
struct Changable<T,false>
{
typedef const T type;
};
template<typename T, bool canChange>
struct Data{
typedef typename Changable<T,canChange>::type DataType;
DataType m_data; //< This makes it const/non-const at compile time.
// This function will also make the return type const/non-const
// at compile time.
DataType& GetDataRef(){ return m_data;}
//However, it seems to me that I still need a second function
//with an explicit "const", which I can't seem to avoid.
DataType& GetDataRef()const{return m_data;}
};
Can I somehow avoid having two const/non-const functions here at compile time using some SFINAE magic? std::enable_if would have been ideal here but it seems to me that const is not a type and that approach may not work. Any suggestions?
Here is an example based on inheritance:
#include <type_traits>
#include <iostream>
template<typename T, bool canChange>
struct Changable { using type = const T; };
template<typename T>
struct Changable<T, true> { using type = std::decay_t<T>; };
template<typename, typename, bool>
struct Base;
template<typename D, typename T>
struct Base<D, T, true> {
using DataType = typename Changable<T, true>::type;
DataType& GetDataRef() { std::cout << "non-const" << std::endl; return static_cast<D*>(this)->m_data; }
};
template<typename D, typename T>
struct Base<D, T, false> {
using DataType = typename Changable<T, false>::type;
DataType& GetDataRef() const { std::cout << "const" << std::endl; return static_cast<const D*>(this)->m_data; }
};
template<typename T, bool canChange>
struct Data: Base<Data<T, canChange>, T, canChange> {
friend class Base<Data<T, canChange>, T, canChange>;
typename Base<Data<T, canChange>, T, canChange>::DataType m_data{};
using Base<Data<T, canChange>, T, canChange>::GetDataRef;
};
int main() {
Data<int, true> d1;
Data<int, false> d2;
d1.GetDataRef();
d2.GetDataRef();
}
As requested, Data has only one definition of the GetDataRef method.
Which one is available, the const one or the other one, depends on the value of canChange.
Note the friend declaration. It allows the base class to access to the private data members of Data.
I think I'd approach this using the templates already available in the standard library. It does not require inheritance or any custom classes.
#include <utility>
template<typename T, bool canChange>
struct Data{
using value_type = T;
using cv_type = std::conditional_t<canChange, value_type, std::add_const_t<value_type>>;
using reference = std::add_lvalue_reference_t<cv_type>;
using const_reference = std::add_lvalue_reference_t<std::add_const_t<cv_type>>;
Data(T t) : m_data(std::move(t)) {}
cv_type m_data; //< This makes it const/non-const at compile time.
// This function will also make the return type const/non-const
// at compile time.
reference GetDataRef(){ return m_data;}
//However, it seems to me that I still need a second function
//with an explicit "const", which I can't seem to avoid.
const_reference GetDataRef() const {return m_data;}
};
int main()
{
Data<int, true> d1 { 10 };
d1.m_data = 12;
const Data<int, true>& rd1 = d1;
auto& a = d1.GetDataRef();
auto& b = rd1.GetDataRef();
a = 12; // compiles fine
// b= 12; won't compile
Data<int, false> d2 { 10 };
const Data<int, false>& rd2 = d2;
auto& c = d2.GetDataRef();
auto& d = rd2.GetDataRef();
// c = 12; // won't compile
// d = 12; // won't compile
}
Now to the question:
Can I somehow avoid having two const/non-const functions here at compile time using some SFINAE magic?
You're almost answering your own question here. SFINAE requires that template arguments are considered in immediate context. Which is a complex way of saying that the expression in std::enable_if<> must depend on some template type.
Unhappily, the template type of T is known by the time the function GetDataRef is evaluated, so enable_if won't help us here.
So if we only want one version of GetDataRef we would indeed have to resort to derivation from a template type (the base class would then be evaluated in immediate context of T).
However, there is a problem even then.
consider:
Data<int, true>& x This is a reference to mutable container containing mutable data
const Data<int, true>& y This is a reference to an immutable container containing mutable data
calling x.GetDataRef() ought to return a mutable reference to an int, otherwise we'll confuse our users.
calling y.GetDataRef() should certainly return a const reference to an int, otherwise again, users may be shocked to learn that a member of a const thing is actually mutable.
Maybe something like this can solve the issue:
#include <type_traits>
#include <iostream>
template<typename T, bool canChange>
struct Changable: std::false_type { using type = const T; };
template<typename T>
struct Changable<T, true>: std::true_type { using type = std::decay_t<T>; };
template<typename T, bool canChange>
struct Data {
using DataTraits = Changable<T, canChange>;
private:
template<typename U>
std::enable_if_t<U::value, typename U::type&>
GetDataRefImpl() { std::cout << "non const" << std::endl; return m_data; }
template<typename U>
std::enable_if_t<not U::value, typename U::type&>
GetDataRefImpl() const { std::cout << "const" << std::endl; return m_data; }
public:
typename DataTraits::type m_data{};
typename DataTraits::type& GetDataRef() { return GetDataRefImpl<DataTraits>(); }
typename DataTraits::type& GetDataRef() const { return GetDataRefImpl<DataTraits>(); }
};
int main() {
Data<int, true> d1;
Data<int, false> d2;
d1.GetDataRef();
d2.GetDataRef();
}
The basic idea is to have both the functions exposed by the class, then forward them internally to the same sfinaed one that is const or non-const (this depends on the value of canChange).
As you can see by running the example, the result is:
non const
const
This is true even if both d1 and d2 have been defined as non const.
The std::enable_if turn on the right internal function at compile time.
Note that I've used what the C++14 offers (as an example std::enable_if_t).
The example can be easily converted to a C++11 based on (std::enable_if_t is nothing more than typename std::enable_if<condition, type>::type and so on).
If C++17 is available to you, have a look at is_const, add_const and remove_const.
Together with if constexpr (), a rather elegant solution should be possible.

Recursively check if function method exists using template

For reasons I want to be able to do this;
vector<int> p = {1, 2};
vector<vector<int>> q = {p, {0, 1}};
auto t = test(p);
auto u = test(q); // Fails with below implementation
Where notably test is templated to accept custom classes which might or might not be iterable for one or two (for now) dimensions. I'm trying to determine what to do by checking if whatever was given has a size function;
template<typename T> struct hasSize {
template<typename U, size_t(U::*)() const> struct SFINAE {};
template<typename U> static char Test(SFINAE<U, &U::size>*);
template<typename U> static int Test(...);
static const bool value = sizeof(Test<T>(0)) == sizeof(char);
};
template<typename iterable> int test(const iterable &x, std::false_type) {
return (int) x;
}
template<typename iterable> int test(const iterable &x, std:: true_type) {
int total = 0;
for(auto &each : x)
total += test(each,
std::integral_constant<bool, hasSize<decltype(each)>::value>());
return total;
}
template<typename iterable> int test(const iterable &view) {
return test(view, std::true_type());
}
I based hasSize on the answers given here after giving up on this answer, since that seemed to be only applicable to member variables, not functions. I also tried a modified version of has_const_reference_op given in first discussion, but this has the same problem.
The error given suggests SNIFAE is not applied a second time;
error C2440: 'type cast':
cannot convert from 'const std::vector<int, std::allocator<_Ty>>' to 'int'
note: No user-defined-conversion operator available that can perform this conversion,
or the operator cannot be called
note: see reference to function template instantiation
'int test<iterable>(const iterable &, std::false_type)' being compiled
with iterable = std::vector<int,std::allocator<int>>
But I have no idea why.
The reason why it fails is that the auto&-typed variable is actually of type const std::vector<int>& with iterable of type const vector<vector<int>>&, and so when queried with decltype -- it yields a reference type that fails the SFINAE check for the size member function existance. So instead of using decltype, just read the value_type from iterable:
total += test(each, std::integral_constant<bool,
hasSize<typename iterable::value_type>::value
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
>());
or remove referenceness/constness from the type produced by decltype:
total += test(each, std::integral_constant<bool,
hasSize<typename std::decay<decltype(each)>::type>::value
// ~~~~~~~~~^
>());
First of all, this isn't the right thing for the general test():
template<typename iterable> int test(const iterable &view) {
return test(view, std::true_type());
}
Since in general test isn't iterable - that's what we need to test for! So instead, we're going to forward this to a series of three functions in a namespace so that we can take advantage of ADL to find everything that we need to find:
namespace adl {
struct helper {};
template<typename iterable>
int test(helper, const iterable &x, std::false_type) {
return (int) x;
}
template<typename iterable>
int test(helper, const iterable &x, std:: true_type) {
int total = 0;
for(auto &each : x) {
// this calls the general one
total += test(helper{}, each);
}
return total;
}
template <typename iterable>
int test(helper, const iterable& x) {
return test(helper{}, x, std::integral_constant<bool, hasSize<iterable>::value>{});
}
}
template<typename iterable>
int test(const iterable &view) {
return test(adl::helper{}, view);
}
We need ADL so that each of the functions can find each other.
Note that it's better to write type traits that yield types instead of just values. Had we written something like:
template <class T, class = void>
struct hasSize : std::false_type { };
template <class T>
struct hasSize<T, void_t<decltype(std::declval<T const&>().size())>>
: std::true_type { };
then our tester overload could be much shorter:
template <typename iterable>
int test(helper, const iterable& x) {
return test(helper{}, x, hasSize<iterable>{});
}
This may not work on VS2013, but you could still add a type typedef to your hasSize.

Rename std::vector to another class for overloading?

Look at this code.
#include <vector>
template<class ...Args>
using other_vector = std::vector<Args...>;
template<class T>
void f(std::vector<T>& ) {}
template<class T>
void f(other_vector<T>& ) {}
int main()
{
other_vector<int> b;
f(b);
return 0;
}
It does not compile, because f is being redeclared. I totally understand the error. However, I need a second class that behaves like std::vector<T>, but will be seen as a different type, so that overloading, like in the above example, would be legal.
What could I do?
Let the new class have std::vector<T> as a base class. This might work, but one should not inherit from std containers.
Let the new class have a member of type std::vector and then redeclare all functions to redirect to the functions of the member. Sounds like a lot of work.
Any better alternative? C++11 or C++14 allowed.
You might try to mess with the allocator:
template<class T>
struct allocator_wrapper : T { using T::T; };
template<class T, class A = std::allocator<T>>
using other_vector = std::vector<T, allocator_wrapper<A>>;
Live example
If you need more than one copy, you can make it a template and take an int template arg for "clone number"
You may wrap your type as follow:
// N allow to have several 'version' of the same type T
template <typename T, int N = 0>
class WrapperType
{
public:
WrapperType() = default;
WrapperType(const WrapperType&) = default;
WrapperType(WrapperType&&) = default;
template <typename ... Ts>
explicit WrapperType(Ts&& ... ts) : t(std::forward<Ts>(ts)...) {}
// implicit conversion
// you may prefer make them explicit or use name get().
operator const T& () const { return t; }
operator T& () { return t; }
private:
T t;
};
And so for your case:
template<class T>
using other_vector = WrapperType<std::vector<T>>;