The problem: I find myself faced with numerous duplicate functions to support different types of almost-identical array-like inputs. For example, a function foo might be available in the following versions:
void foo (int v); // single value, 99% of all use cases.
void foo (std::initializer_list<int> v);
void foo (const std::vector<int> &v);
void foo (int *v, int size);
This duplication bothers me. I would like to have a single function foo, that may be called with any kind of array-like data (with a single value obviously being seen as an array of size 1).
Possible solutions include:
Always use the vector version. This incurs some overhead for memory allocation on every use, and since 99% of my uses are for single values I find this undesirable.
Have an interface specifying an iterator pair. This again falls flat when attempting to call the function for a single value.
Have some sort of abstraction for array-like data that can handle all of the desired input types. This is a promising approach, but I do run into some trouble...
My implementation is called mem_range, which presents a vector-like interface (only including operations that do not change the size of the vector, obviously). The various types of arrays are supposed to be handled through different constructors of mem_range.
I have trouble specifying the constructor that is supposed to take std::array. The problem is the array size, which is part of the template definition - I cannot figure out how to create a constructor that will accept arrays of any size.
template<typename T>
class mem_range {
public:
mem_range (T *begin, T *end) { } // ok
mem_range (std::vector<T> &vec) { } // ok
template<int array_size>
mem_range<array_size> (std::array<T, array_size> &arr) { } // not ok
}
The last constructor yields "error C2988: unrecognizable template declaration/definition" on MSVC2015. I've gone through quite a few variations now, but nothing that makes the compiler happy.
Just to be clear, based on answers I've read on similar questions here on stackoverflow:
Resizing the array-like data in any way is not in scope. If I wanted that capability I'd just pass an std::vector.
I'm aware there are many questions with similar titles. None of these appear to have decent answers, usually getting no further than "why do you want this?".
I'm trying to make this work on MSVC2015 and modern GCC, so C++14/17 are fine (as far as supported).
When declaring the templated constructor, the template is understood to belong to the constructor function, so you don't need to specify it there.
You are also missing a closing bracket > after the array argument.
So the constructor should look like this:
template<int array_size>
mem_range(std::array<T, array_size>) { }
And of course, you should consider passing the array object as a reference to a constant, and using the correct type (see e.g. this std::array reference`), i.e.
template<std::size_t array_size>
mem_range(std::array<T, array_size> const&) { }
You can make array_size an optional value of the template class.
template<typename T, int array_size=0>
class mem_range {
public:
mem_range (T *begin, T *end) { } // ok
mem_range (std::vector<T> &vec) { } // ok
mem_range (std::array<T, array_size> &array) { }
}
Related
I'm working on a program where some data is statically allocated and some is dynamically allocated. Now I want to have another type that can be called with any template of the type as its argument.
#include <array>
#include <vector>
template <int size> class Foo {
std::array<int, size> data;
public:
int& operator[](std::size_t idx) {return data[idx];}
};
template <> class Foo<-1> {
std::vector<int> data;
public:
int& operator[](std::size_t idx) {return data[idx];}
};
// option 1- polymorphism
struct FooCaller {
virtual void operator()(Foo data) = 0; // how would I make this work with both forms of Foo?
};
// option 2- generic programming
template <class T> concept CanCallFoo = requires (const T& t) {
t(std::declval<Foo&>()); // how do I ensure that this can call any overload of Foo?
};
Both methods would be fine, but I'm not sure how to go about this. Because the full code is more complex, I'd rather not have both Foos inherit from a base.
A callable F could write a restriction that it can be called by Foo<x> such that an arbitrary function of x must be true to be valid.
In order for your "can be called with any Foo" test to work, you would have to invert an arbitrary function at compile time.
There is no practical way to do this short of examinjng all 2^32 possible values of x. No, really. The problem you have is that the type F is possibly too powerful for you to determine its properties. This is related to Halt and Rice's theorem and the fact that template metaprogramming and C++ overload resolution is Turing complete (only related, because 2^32 is finite).
In the other case, you could type erase. Write a type RefAnyFoo/AnyFooValue that can be constructed from any Foo type and "type erases" the operations you want, like how std::function<void(int)> type erases. It could either duck type the Foo or actually restrict to instsnces of types made from the template.
Then your interface is one that takes a AnyFooValue/RefAnyFoo (depending if you are talking about copies or references).
Now, flipping this over, you can write a concept that accepts F that take RefFooAny. This isn't quite what you asked for, but plausibly you have an X/Y problem; you had a real problem, came up with incomplete solutions, then asked about how to get your solutions working, instead of the original problem.
Similarly, it is possible you only care about certain ducktype properties of Foo<?> and not the specific type. Then a concept that checks those ducktypes could be used by your callable; this again deosn't solve your problem, as much as it flips it upside down, because you cannot verify a callable accepts an entire concept from outside the callable.
I tried to add my own constructor for std::array type, but I don't sure is it possible and how to do that...
I tried sth like this:
typedef unsigned char byte_t;
namespace std {
template<std::size_t _Nm>
array::array(std::vector<byte_t> data)
{
// Some content
}
}
I want to create very easy mechanism to converting std::vector<byte_t> to std::array<byte_t, size>.
It is possible?
How can I do that?
I am using C++14 (and I cannot use in my project newer standards)
Constructors are special member functions, they must be declared within the class definition. It is not possible to add constructors to an existing class without changing the class definition.
You can achieve a similar effect using a factory function:
template<size_t N, class T>
std::array<T, N> as_array(std::vector<T> const& v) {
std::array<T, N> a = {};
std::copy_n(v.begin(), std::min(N, v.size()), a.begin());
return a;
}
int main() {
std::vector<byte_t> v;
auto a = as_array<10>(v);
}
I doubt the necessity of such a conversion, at the exception of a function which expect a std::array and cannot be modified. You have two alternatives :
Use the good old T* raw array underneath the vector. After all, std::array is designed to easily manage the equivalent of a fixed-size C array.
Make your code unaware of containers by using functions on iterators. This is design path the modern c++ expect. You can take a look at the possible implementation of various operations in the algorithm library.
I'm porting some Fortran90 code to C++ (because I'm stupid, to save the "Why?!").
Fortran allows specification of ranges on arrays, in particular, starting at negative values, eg
double precision :: NameOfArray(FirstSize, -3:3)
I can write this in C++ as something like
std::array<std::array<double, 7>, FirstSize> NameOfArray;
but now I have to index like NameOfArray[0:FirstSize-1][0:6]. If I want to index using the Fortran style index, I can write perhaps
template <typename T, size_t N, int start>
class customArray
{
public:
T& operator[](const int idx) { return data_[idx+start]; }
private:
std::array<T,N> data_;
}
and then
customArray<double, 7, -3> NameOfArray;
NameOfArray[-3] = 5.2;
NameOfArray[3] = 2.5;
NameOfArray[4] = 3.14; // This is out of bounds,
// despite being a std::array of 7 elements
So - the general idea is "Don't inherit from std::'container class here'".
My understanding is that this is because, for example, std::vector does not have a virtual destructor, and so should not (can not?) be used polymorphically.
Is there some other way I can use a std::array, std::vector, etc, and get their functions 'for free', whilst overriding specific functions?
template<typename T, size_t N>
T& std::array<T,N>::operator[](const int idx) { ... };
might allow me to override the operator, but it won't give me access to knowledge about a custom start point - making it completely pointless. Additionally, if I were to optimistically think all my customArray objects would have the same offset, I could hardcode that value - but then my std::array is broken (I think).
How can I get around this? (Ignoring the simple answer - don't - just write myArray[idx-3] as needed)
There's no problem with inheriting standard containers. This is only generally discouraged because this imposes several limitations and such an inheritance is not the way how inheritance was originally predicted in C++ to be used. If you are careful and aware of these limitations, you can safely use inheritance here.
You just need to remember that this is not subclassing and what this really means. In particular, you shouldn't use pointers or references to the object of this class. The problem might be if you pass a value of MyVector<x>* where vector<x>* was expected. You should also never create such objects as dynamic (using new), and therefore also delete these objects through the pointer to the base class - simply because destructor call will not forward to your class's destructor, as it's not virtual.
There's no possibility to prevent casting of the "derived pointer" to the "base pointer", but you can prevent taking a pointer from an object by overloading the & operator. You can also prevent creating objects of this class dynamically by declaring an in-class operator new in private section (or = delete should work as well).
Don't also think about private inheritance. This is merely like containing this thing as a field in private section, except the accessor name.
A range converter class could be the solution although you would need to make it yourself, but it would allow you to get the range size to initialize the vector and to do the conversion.
Untested code:
struct RangeConv // [start,end[
{
int start, end;
RangeConv(int s, int e) : start(s), end(e) { }
int size() const { return end - start; }
int operator()(int i) { return i - start; } // possibly check whether in range
}
RangeConv r(-3, 3);
std::vector<int> v(r.size());
v[r(-3)] = 5;
so should not (can not?) be used polymorphically.
Don't give up too soon. There are basically two issues to consider with inheritance in C++.
Lifetime
Such objects, derived classes with non-virtual destructors in the base, can be used safely in a polymorphic fashion, if you basically follow one simple rule: don't use delete anywhere. This naturally means that you cannot use new. You generally should be avoiding new and raw pointers in modern C++ anyway. shared_ptr will do the right thing, i.e. safely call the correct destructor, as long as you use make_shared:
std:: shared_ptr<Base> bp = std:: make_shared<Derived>( /* constructor args */ );
The type parameter to make_shared, in this case Derived, not only controls which type is created. It also controls which destructor is called. (Because the underlying shared-pointer object will store an appropriate deleter.)
It's tempting to use unique_ptr, but unfortunately (by default) it will lead to the wrong deleter being used (i.e. it will naively use delete directly on the base pointer). It's unfortunate that, alongside the default unique_ptr, there isn't a much-safer-but-less-efficient unique_ptr_with_nice_deleter built into the standard.
Polymorphism
Even if std::array did have a virtual destructor, this current design would still be very weird. Because operator[] is not virtual, then casting from customArray* to std:: array* would lead to the wrong operator[]. This isn't really a C++-specific issue, it's basically the issue that you shouldn't pretend that customArray isa std:: array.
Instead, just decide that customArray is a separate type. This means you couldn't pass an customArray* to a function expecting std::array* - but are you sure you even want that anyway?
Is there some other way I can use a std::array, std::vector, etc, and get their functions 'for free', whilst overloading specific functions?
This is a good question. You do not want your new type to satisfy isa std::array. You just want it to behave very similar to it. As if you magically copied-and-pasted all the code from std::array to create a new type. And then you want to adjust some things.
Use private inheritance, and using clauses to bring in the code you want:
template <typename T, size_t N, int start>
struct customArray : private std::array<T,N>
{
// first, some functions to 'copy-and-paste' as-is
using std::array<T,N> :: front;
using std::array<T,N> :: begin;
// finally, the functions you wish to modify
T& operator[](const int idx) { return data_[idx+start]; }
}
The private inheritance will block conversions from customArray * to std::array *, and that's what we want.
PS: I have very little experience with private inheritance like this. So many it's not the best solution - any feedback appreciated.
General thought
The recommendation not to inherit from standard vector, is because this kind of construct is often misunderstood, and some people are tempted to make all kind of objects inherit from a vector, just for minor convenience.
But this rule should'nt become a dogma. Especially if your goal is to make a vector class, and if you know what you're doing.
Danger 1: inconsistency
If you have a very important codebase working with vectors in the range 1..size instead of 0..size-1, you could opt for keeping it according to this logic, in order not to add thousands of -1 to indexes, +1 to index displayed, and +1 for sizes.
A valid approach could be to use something like:
template <class T>
class vectorone : public vector<T> {
public:
T& operator[] (typename vector<T>::size_type n) { return vector<T>::operator[] (n-1); }
const T& operator[] (typename vector<T>::size_type n) const { return vector<T>::operator[] (n-1); }
};
But you have to remain consitent accross all the vector interface :
First, there's also a const T& operator[](). If youd don't overload it, you'll end up having wrong behaviour if you have vectors in constant objects.
Then, and it's missing above, theres's also an at() which shall be consitent with []
Then you have to take extreme care with the constructors, as there are many of them, to be sure that your arguments will not be misinterpreted.
So you have free functionality, but there's more work ahead than initially thougt. The option of creating your own object with a more limited interface, and a private vector could in the end be a safer approach.
Danger 2:more inconsistency
The vector indexes are vector<T>::size_type. Unfortunately this type is unsigned. The impact of inherit from vector, but redefine operator[] with signed integer indexes has to be carefully analysed. This can lead to subtle bugs according to the way the indexes are defined.
Conclusions:
There's perhap's more work that you think to offer a consistent std::vector interface. So in the end, having your own class using a private vector could be the safer approach.
You should also consider that your code will be maintained one day by people without fortran background, and they might have wrong assumptions about the [] in your code. Is going native c++ really out of question ?
It doesn't seem that bad to just stick with composition, and write wrappers for the member functions you need. There aren't that many. I'd even be tempted to make the array data member public so you can access it directly when needed, although some people would consider that a bigger no-no than inheriting from a base class without a virtual destructor.
template <typename T, size_t N, int start>
class customArray
{
public:
std::array<T,N> data;
T& operator[](int idx) { return data[idx+start]; }
auto begin() { return data.begin(); }
auto begin() const { return data.begin(); }
auto end() { return data.end(); }
auto end() const { return data.end(); }
auto size() const { return data.size(); }
};
int main() {
customArray<int, 7, -3> a;
a.data.fill(5); // can go through the `data` member...
for (int& i : a) // ...or the wrapper functions (begin/end).
cout << i << endl;
}
So what I want to do is extend the existing vector class in my program to allow me to say this,
vector<string>* vec = new vector<string>(){"Value1","Value2"};
or
vector<string>* vec = new vector<string>({"Value1","Value2"});
or
vector<string> vec = {"Value1","Value2"};
I know I can accomplish something like this but doing this,
string temp[] = {"Value1","Value2"};
vector<string> vec(temp, temp+ sizeof(temp) / sizeof( temp[0] ) );
This uses the vectors iterator constructor but can't I remove the extra line?
I know in C# you can add whatever you want to existing things by using the partial key word like this,
public partial class ClassName
{
ClassName(Stuff stuff)
{
}
void AmazingNewMethod()
{
}
}
Does C++ have a nifty trick like this somewhere?
Do I have to inherit vector and build a customVector that has a constructor that behind the scenes does the iterator constructor thing?
Maybe wrap those lines in a static Helper Function call that sets it by Reference and add it to a toolbox class somewhere?
I feel like lots of programmers have hit this problem. Are there any elegant solutions out there?
Thanks.
Edit: fixed the title to mention this is an Initializer List constructor.
In C++11 there would be initializer lists to suite this approach. As you're mentioning .NET I now assume that you're using MS Visual Studio. Microsoft does NOT implement initializer lists, therefore the easiest way to accomplish something like that would be a function that returns the vector with all the elements added.
On the partial thing: C++ does not offer a feature in the same vein as .NET's partial classes.
The C++ 2011 way is to accept an std::initializer_list<T> as a constructor argument:
#include <initializer_list>
template <typename T>
class foo {
T *d_array;
public:
foo(std::initializer_list<T> list)
: d_array(new T[list.size()]) {
std::copy(list.begin(), list.end(), this->d_array);
}
foo(foo const&);
foo& operator= (foo const&);
~foo() { delete[] this->d_array; }
};
The above clearly only concentrates on how use an std::initializer_list<T>. To actually do the allocation internally you'd allocate raw memory and construct the object in-place. However, this wasn't what the question is about.
With respect to adding this support to std::vector<T>: you don't have to! In C++ 2011 std::vector<T> can be initialized with an std::initializer_list<T>. In C++ 2003 you can't do this. The best you could do is to support construction from an array, using a constructor looking something like this:
template <typename T>
template <typename S, int Size>
foo<T>::foo(S const (&array)[Size])
d_array(new T[Size]) {
std::copy(array, array + Size, d_array);
};
However, there is no way to extend an existing without changing its type. To avoid reimplementing most of the members you could publically inherit from the type you want to extend and add all required constructors (these are not inherited; in C++ 2011 you could inherit the existing constructors but then, with C++ 2011 you wouldn't need to do any of this anyway).
An alternative you might want to use with C++ 2003 is to create a factor function taking a built-in array, i.e. something like this:
template <typename T, typename S, int Size>
std::vector<T>
make_vector(S const (&array)[Size]) {
return std::vector<T>(array, array + Size);
}
char const* init[] = { "Hello", "World" };
std::vector<std::string> value = make_vector<std::string>(init);
C++ templates are generally assimilated to creators of bloat, and the Shim idea deals with exactly that: making the template just a thin wrapper over a regular function. It's a really great way to cut down on the bloat.
For example, let's use a simple shim:
//
// Shim interface
//
struct Interface {
virtual void print(std::ostream& out) const = 0;
}; // struct Interface
std::ostream& operator<<(std::ostream& out, Interface const& i) {
i.print(out);
return out;
}
template <typename T>
struct IT: public Interface {
IT(T const& t): _t(t) {}
virtual void print(std::ostream& out) const { out << _t; }
T const& _t;
};
template <typename T>
IT<T> shim(T const& t) { return IT<T>(t); }
Now, I can use it like so:
void print_impl(Interface const& t);
template <typename T>
void print(T const& t) { print_impl(shim(t)); }
And no matter how print_impl is implemented, print remains very lightweight and should be inlined. Easy peasy.
C++11 however introduces variadic templates. The typical urge then is to reimplement all unsafe C-variadics with C++11 variadic templates, even Wikipedia suggests so with a printf implementation.
Unfortunately, Wikipedia's implementation does not deal with positional arguments: the kind that allows you to specify print the 3rd parameter there, etc... It would be easy, if only we had a function with this prototype:
void printf_impl(char const* format, Interface const* array, size_t size);
or similar.
Now, how do we bridge from the original interface:
template <typename... T>
void printf(char const* format, T const&... t);
to the signature above ?
One difficulty with the shims is that they rely on the binding to const-ref behavior to extend the lifetime of the temporary wrapper created just enough without having to allocate memory dynamically (they would not be cheap if they did).
It seems difficult though to get that binding + the array transformation in one step. Especially because arrays of references (and pointer to references) are not allowed in the language.
I have a beginning of a solution, for those interested:
//
// printf (or it could be!)
//
void printf_impl(char const*, Interface const** array, size_t size) {
for (size_t i = 0; i != size; ++i) { std::cout << *(array[i]); }
std::cout << "\n";
}
template <typename... T>
void printf_bridge(char const* format, T const&... t) {
Interface const* array[sizeof...(t)] = { (&t)... };
printf_impl(format, array, sizeof...(t));
}
template <typename... T>
void printf(char const* format, T const&... t) {
printf_bridge(format, ((Interface const&)shim(t))...);
}
however you will note the introduction of a supplementary step, which is a bit annoying. Still, it appears to work.
I would be very grateful if someone had a better implementation to propose.
#Potatoswatter suggested using initializer lists, which helps a bit (no range-for there).
void printf_impl(char const*, std::initializer_list<Interface const*> array) {
for (Interface const* e: list) { std::cout << *e; }
std::cout << "\n";
}
template <typename... T>
void printf_bridge(char const* format, T const&... t) {
printf_impl(format, {(&t)...});
}
But still does not solve the intermediate function issue.
Making it lightweight hinges on eliminating the type parameterization. Your shim potentially instantiates something heavy-duty with the expression out << _t, so it might not really be a good example.
C varargs handles the problem by implicitly casting everything to intptr_t. If you only want to replicate C printf functionality, you can do the same with reinterpret_cast and an initializer_list.
template <typename... T>
void printf(char const* format, T const&... t) {
printf_impl(format, { reinterpret_cast< std::intptr_t >( t ) ... } );
}
This is obviously suboptimal, but shims are inherently limited. You could do something else with polymorphic types in the initializer_list if you wanted.
In any case, this is exactly what initializer_list is meant for. It can only be constructed from a braced-init-list, making its size a compile-time constant. But the size can only be read back as a runtime constant. So its only practical use is to funnel templates differing only in list length to a common, variable-length implementation.
Add to that the lifetime semantics of initializer_list arguments — the objects are created in a contiguous array on the stack and die when the function call statement ends — and initializer_list looks a lot like <varargs>! (Edit: or your solution, which I have now actually gone back and read :vP )
Edit: Since containers can't directly store polymorphic objects, and smart pointers aren't appropriate for temporary argument objects, implementing polymorphism would require taking pointers to temporaries. Ugly, but legal due to the lifetime guaranteed for temporary objects:
template <typename... T>
void printf(char const* format, T const&... t) {
printf_impl(format, std::initializer_list< Interface const * >
{ & static_cast< Interface const & >( shim(t) )... } );
}
If you can use homogenous (same size and alignment in memory) types take a look at that:
// thin template layer over regular class/methods
template< typename T, typename... Contracts>
inline void Container::bindSingleAs(){
isMultiBase< T, Contracts...>(); //compile time test
priv::TypeInfoP types[ sizeof...( Contracts)]
{ &typeid( Contracts)... };
priv::SharedUpcastSignature upcasts[ sizeof...( Contracts)]
{ &priv::shared_upcast< T, Contracts>... };
// dispatch over non-template method.
container->bindSingleAs( &typeid(T), types, upcasts, sizeof...( Contracts));
}
Now after editing due to comments, I think there are 2 conflicting requisites.
Want an array parameter
Want no copy overhead
If the printf_impl function require an array as parameter, then this mean that the array elements should have the same disposition in memory (that means that if 1 element is 64 bytes that forces all other elements to be 64 bytes aligned even if they are 1 byte..) hence a copy is necessary, or at least the copy to a pointer to a fixed location, so it is definitely NOT POSSIBLE do what OP wanted.
We can still build that array but we are constrained:
We Don't want copying at all, then we should statically declare the type of the array, this force us to build a third type.
auto Array = MakeArray( /* values*/);
printf( Array);
We accept copying, so we build the array inside the function, since values are not known we can hide array from user but we have to copy the parameters to fixed memory locations, however we still have the array hided under the hood.
Heap allocation, that allows to pass parameters in a very compact array, however the parameters have to reside elsewhere and heap allocation may be costly.
The first solution is to accept an extra complexity in coding by creating a statically typed array wich elements can be addressed (all aligned to biggest element), however that is suboptimal since that increase the size of the object wich can hit anyway performance (if that array lives even after the function call)
The second solution hides the complexity behind the template interface, however it cannot avoid the performance cost of copying values temporarily to an array identical to the one of the first solution.
So, it is not possible doing so, sorry. The other answer falls between number 2 and 3. All other possible answers would be within one of the 3 categories.