I have a little problem and I'm working on it for several hours but can't find a solution. Hope you will help me.
Here is my class:
#include <iostream>
#include <iterator>
template <typename T> class Array{
private:
size_t size;
T *newArray;
public:
class Iterator:public std::iterator<std::output_iterator_tag, T>{
T *p;
public:
Iterator(T*x):p(x){}
T& operator*() {return *p;}
};
Array (size_t size = 10): size(size), newArray(new T[size]){};
Iterator begin(){return (Iterator(newArray));}
T printBegin(typename Array<T>::Iterator it){ return *it;}
template <typename E>
T printBegin(typename Array<E>::Iterator it){ return (T)*it;}
};
And here is Main:
using namespace std;
int main(){
Array<int> x;
Array<int> y;
cout << y.printBegin(x.begin()); // prints 0 OK
Array<double> p;
// cout << p.printBegin(x.begin());
return 0;
}
The first cout works fine but the line that is commented gives this : error: no matching function for call to ‘Array<double>::printBegin(Array<int>::Iterator)’
I don't understand because the last line in my Array class matches (normally) for this function call
The problem is that you want to deduce the E in Array<E>::Iterator from x.begin() that is an Array<int>::Iterator. But that is simply not possible.
Your best option is probably to write:
template <typename IT>
T printBegin(IT it){ return (T)*it;}
If, for any reason, you need to use the E type, then it is better to add a nested typedef:
class Iterator:public std::iterator<std::output_iterator_tag, T>{
public:
typename T array_member_type;
//...
};
And then:
template <typename IT>
T printBegin(IT it){
typedef typename IT::array_member_type E;
return (T)*it;
}
Wait! Your iterator derives from std::iterator so the typedef already exists. No need to redefine:
template <typename IT>
T printBegin(IT it){
typedef typename IT::value_type E;
return (T)*it;
}
Your question is very similar to another question about template deduction.
The compiler cannot deduct the type E from Array<E>::Iterator. Why should it be able to? Two different types E could share the same iterator type.
What you are really saying to the compiler is:
"Is there a type "E" for which Array<E>::Iterator is this type?"
Related
Im trying to create a class as container-wrapper, something like this
#include <vector>
template <typename T, typename U>
class Test {
T<U> list;
};
int main() {
Test<std::vector, int> test;
}
But this wont work. I know it will work when I use it like this
#include <vector>
template <typename T>
class Test {
T list;
};
int main() {
Test<std::vector<int>> test;
}
but how would I write my insert?
template <typename T>
class Test {
T list;
public:
void insert(??? element) {
...
}
};
TIA, Narase
The easiest one would be
template <typename T>
class Test {
....
void insert(const typename T::value_type& element);
And/or, for completeness and move semantics compliance:
void insert(typename T::value_type&& element);
But this wont work.
With your first snippet of Test, since std::vector has two template parameters, value_type and allocator_type, we must specify the existence of these template parameters in the declaration of T using template template parameters as follows.
Here I use variadic one and then T<U...> becomes legal for
T = std::vector and compilation errors are removed.
how would I write my insert?
The following code also shows an implementation example of Test::insert.
Since this method can accept both lvalue and rvalue references in C++11 and over, here I apply the forwarding reference (which is what Scott Meyers calls universal reference,) to it.
In this approach, we does not need to specify the value type of Test::list in the Test::insert definition and passing wrong types to Test::insert causes compilation errors.
If you need the value type of std::vector, the member type std::vector::value_type is available:
template <template<class...> class T, class ...U>
class Test
{
T<U...> list;
public:
template<class ...V>
void insert(V&& ...element) {
list.insert(std::forward<V>(element)...);
}
typename T<U...>::iterator begin() noexcept {
return list.begin();
}
typename T<U...>::iterator end() noexcept {
return list.end();
}
using value_type = typename T<U...>::value_type;
};
This is an usage example with std::vector:
DEMO (std::vector)
static_assert(
std::is_same<Test<std::vector, int>::value_type, int>::value, "oops!"); // OK.
Test<std::vector, int> test; // OK
test.insert(test.end(), 11);
test.insert(test.end(), 99);
for(auto it = test.begin(); it != test.end(); ++it){
std::cout << *it << std::endl;
}
As another example, this wrapper class also works with std::map as follows:
DEMO (std::map)
static_assert(
std::is_same<Test<std::map, int, int>::value_type, std::pair<const int, int>>::value, "oops!"); // OK.
Test<std::map, int, int> test; // OK
test.insert(std::make_pair(1, 11));
test.insert(std::make_pair(2, 99));
for(auto it = test.begin(); it!= test.end(); ++it){
std::cout << it->first << ", " << it->second << std::endl;
}
Finally, this is a fixed version of your second snippet:
DEMO (std::vector)
DEMO (std::set)
template <class T>
class Test
{
T list;
public:
template<class ...V>
void insert(V&& ...element) {
list.insert(std::forward<V>(element)...);
}
typename T::iterator begin() noexcept {
return list.begin();
}
typename T::iterator end() noexcept {
return list.end();
}
using value_type = typename T::value_type;
};
Basicly ,I want to make a function behave differently for a vector(type) parameter and a non-vector type parameter .
#include <vector>
using namespace std;
template <typename type>
struct is_vector {
static const bool value = false;
};
template <typename type>
struct is_vector<vector<type>>
{
static const bool value = true;
};
template <typename type>
type read()
{
if (is_vector<type>::value)
{
type vec(10);
vec.front()=1;//left of '.front' must have class/struct/union
return vec;
}
else
{
return{};
}
}
int main()
{
auto i= read<int>();
}
I want to return a vector while using vector as the typename ,return an int while using int as the typename .
But since is_vector(int)::value returns false ,why would my compiler reports "left of '.front' must have class/struct/union" ?How can I make it work ?
What I want to achieve is to correctly deserialize a string to a vector(type) or a vector(vector(type)) .
I need to recursively call the read function ,while passing a multidemonsional vector as a template parameter ,but the compiler forbids me to do it .
template <typename type>
struct is_vector {
static const bool value = false;
};
template <typename type>
struct is_vector<vector<type>>
{
static const bool value = true;
};
template <typename type>
type read(char*& str)
{
if (is_vector<type>::value)
{
type vec(read<uint8_t>(str));
for (auto& e : vec)
e = read<type::value_type>(str);
return vec;
}
return *reinterpret_cast<type*>((str += sizeof(type)) - sizeof(type));
}
So I tried specialization .
template<>
vector<int> read<vector<int>>(char*& str)
{
vector<int> vec(read<uint8_t>(str));
for (auto& e : vec)
e = read<int>(str);
return vec;
}//works
template <typename type>
template <>
vector<type> read<vector<type>>(char*& str)
{
vector<type> vec(read<uint8_t>(str));
for (auto& e : vec)
e = read<type>(str);
return vec;
}//don't work
Do I really need to manually rewrite my read function for every kind of types I use ?
(like vector(vector(vector(int)))?)
You want a function template foo<R> that is parameterized at least
by return type R, and you want a specialized implementation
when R = std::vector<U>, for arbitrary type U.
It doesn't matter what the arguments of foo<R> may be, so for illustration
we'll assume there aren't any. Here's how you do that:
Define a trait template as follows:
template<typename T>
struct is_vector
{
static constexpr bool value = false;
};
template<template<typename...> class C, typename U>
struct is_vector<C<U>>
{
static constexpr bool value =
std::is_same<C<U>,std::vector<U>>::value;
};
With this,
is_vector<T>::value
will be true at compiletime if and only if T = std::vector<U>, for some U.
Then define two overloads of foo<R>() on the following lines:
template <typename R>
std::enable_if_t<!is_vector<R>::value,R> foo()
{
// Your non-vector implementation instead of...
std::cout <<
"In non-vector specialization of `foo<R>()`\n";
return R();
}
template <typename R>
std::enable_if_t<is_vector<R>::value,R> foo()
{
// Your vector implementation instead of...
std::cout <<
"In vector specialization of `foo<R>()`\n";
return R();
}
These two overloads are mutually exclusive and jointly exhaustive. The
first overload pans out to be legal code if and only if is_vector<R>::value is false. The
second overload pans out to be legal code if and only if is_vector<R>::value is true.
That's thanks to the behaviour of std::enable_if,
which you should study and understand.
When the compiler needs to pick one these template overloads to implement some
call foo<type>() that it finds in your code, it discovers that exactly one of the overloads
won't even compile when type is plugged in for the template parameter R. The first one won't compile if
type is some std::vector<U> and the second one won't compile if type is not some
std::vector<U>. Helpfully, the compiler picks the one that it can compile.
That's called SFINAE ("Substitution Failure Is Not An Error"),
and it's the solution of your problem.
Here's an illustrative program:
#include <vector>
#include <type_traits>
#include <iostream>
template<typename T>
struct is_vector
{
static constexpr bool value = false;
};
template<template<typename...> class C, typename U>
struct is_vector<C<U>>
{
static constexpr bool value =
std::is_same<C<U>,std::vector<U>>::value;
};
template <typename R>
std::enable_if_t<!is_vector<R>::value,R> foo()
{
// Your non-vector implementation instead of...
std::cout <<
"In non-vector specialization of `foo<R>()`\n";
return R();
}
template <typename R>
std::enable_if_t<is_vector<R>::value,R> foo()
{
// Your vector implementation instead of...
std::cout <<
"In vector specialization of `foo<R>()`\n";
return R();
}
int main()
{
auto i = foo<int>();
(void)i;
auto vc = foo<std::vector<char>>();
(void)vc;
return 0;
}
which will output:
In non-vector specialization of `foo<R>()`
In vector specialization of `foo<R>()`
(gcc 6.1/clang 3.8, -std=c++14 see live)
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.
I've searched for this question and I can't find anything on it. Is there a better way to query something like this in Google or can anyone provide a link or links or a fairly detailed explanation? Thanks!
EDIT: Here's an example
template< typename T, size_t N>
struct Vector {
public:
Vector() {
this->template operator=(0);
}
// ...
template< typename U >
typename boost::enable_if< boost::is_convertible< U, T >, Vector& >::type operator=(Vector< U, N > const & other) {
typename Vector< U, N >::ConstIterator j = other.begin();
for (Iterator i = begin(); i != end(); ++i, ++j)
(*i) = (*j);
return *this;
}
};
This example is from the ndarray project on Google Code and is not my own code.
Here is an example where this->template is required. It doesn't really match the OP's example though:
#include <iostream>
template <class T>
struct X
{
template <unsigned N>
void alloc() {std::cout << "alloc<" << N << ">()\n";}
};
template <class T>
struct Y
: public X<T>
{
void test()
{
this->template alloc<200>();
}
};
int main()
{
Y<int> y;
y.test();
}
In this example the this is needed because otherwise alloc would not be looked up in the base class because the base class is dependent on the template parameter T. The template is needed because otherwise the "<" which is intended to open the template parameter list containing 200, would otherwise indicate a less-than sign ([temp.names]/4).
It used to disambiguation, and
// maybe: (handle->appendArray < 13) > (myarray);
handle->appendArray<13>(myarray);
Maybe some compilers can deduce it automatically.
When extending a class that depends on a template parameter, this kind of become a dependent name.
The problem is that while performing two phase name lookup, the compiler can't know where he can find the function hello. He cannot know it comes from the parent. Because template specialization is a thing, Base<int> and Base <double> could be two completely different clas swith different functions and members.
With the this keyword added, the compiler know that hello must be a member function.
Without that, it could be either a member function or non-member function.
#include <iostream>
template <class T>
class Base {
public:
void hello() {std::cout << "hello\n";}
void hello1() {std::cout << "hello1\n";}
template <unsigned N>
void hello2() {std::cout << "hello2<" << N << ">()\n";}
};
template <class T>
class Drivered: public Base<T> {
public:
using Base<T>::hello;
void test()
{
hello();
this->hello1();
this->template hello2<200>();
}
};
int main() {
Drivered<int> d;
d.test();
}
【1】https://stackoverflow.com/a/39667832/4268594
Let's say I have a template:
template <class N, class I>
void add(N* element, std::list<N*> & container, I (N::*f)() const,
std::string successmsg, std::string exceptmsg) {
//...
}
And I want to call it for a list of Base Class pointers to a derivative class.
add(newAirplane, airplanes, &Airplane::getRegistration,
"Added!", "Error: Existent!");
Airplane inherits from AirplaneType.
Of course, it doesn't compile, N is first defined as AirplaneType and then as Airplane.
I added a virtual getRegistration # AirplaneType but of course, the compiler gives out a vtable error.
What's the proper way to solve this? AirplaneType has no registration attribute and I'm not interested in it having one. I also wanted to avoid virtual getRegistration() const {return "";}
Any suggestions for good practice?
EDIT:
Thanks for answers, but still not working. I think I have found the remaining problem, but not its solution:
void Airline::addAirplane(AirplaneType* airplane) {
add(newAirplane, airplanes, &Airplane::getRegistration,
"Added!", "Error: Existent!");
}
The type of pointer received is AirplaneType, not Airplane.
airplanes is a list of AirplaneType pointers.
You need another template parameter, because you care about two different classes - the type of the pointer (and hence the member function you're going to call with it), and the type of the container:
#include <list>
struct AirplaneType {
};
struct Airplane : AirplaneType {
int check() const { return 3; }
};
template <typename T, typename U, typename I>
void add(T* element, std::list<U*> & container, I (T::*f)() const) {
container.push_back(element);
I i = (element->*f)();
}
int main() {
std::list<AirplaneType*> ls;
Airplane a;
add(&a, ls, &Airplane::check);
}
In this case my add function doesn't really use the fact that container is a list, so a more sensible version might be:
template <typename T, typename U, typename I>
void add(T* element, U & container, I (T::*f)() const) {
container.push_back(element);
I i = (element->*f)();
}
And then again, you could abstract further:
template <typename T, typename U, typename AUF>
void add(T element, U & container, AUF func) {
container.push_back(element);
typename AUF::result_type i = func(element);
}
... but that's slightly less convenient for the caller:
#include <functional>
add(&a, ls, std::mem_fun(&Airplane::check));
Any suggestions for good practice?
Don't create containers of raw pointers.
Edit: to get this working with a virtual function, with each of my options:
#include <list>
#include <functional>
#include <iostream>
struct AirplaneType {
virtual int check() const { return 0; }
};
struct Airplane : AirplaneType {
int check() const { std::cout << "check\n"; return 3; }
};
template <typename T, typename U, typename I>
void add(U* element, std::list<T*> & container, I (U::*f)() const) {
container.push_back(element);
I i = (element->*f)();
}
template <typename T, typename U, typename AUF>
void add2(T element, U & container, AUF func) {
container.push_back(element);
typename AUF::result_type i = func(element);
}
int main() {
std::list<AirplaneType*> ls;
Airplane a;
add(static_cast<AirplaneType*>(&a), ls, &AirplaneType::check);
add2(&a, ls, std::mem_fun(&AirplaneType::check));
}
Output is:
check
check
which shows that the override is correctly called even though the function pointer was taken to AirplaneType::check, not Airplane::check.
You need to add an additional template parameter for the common base since C++ does not handle contravariant types. That is, std::list<Airplane*> is an entirely different type from std::list<AirplaneType*>, and no implicit conversion can occur from the list of pointers to the most derived to the least derived.. So, effectively your add function would need to become:
template <class N, class I, class B>
void add(N* element, std::list<B*> & container, I (N::*f)() const,
std::string successmsg, std::string exceptmsg)