Template specification of any kind of array - c++

I'm trying to get rid of void* + size approach to storing arbitrary array types in the same container.
At the moment it looks somewhat like this:
#include <iostream>
#include <map>
#include <string>
#include <cstddef>
struct fat_pointer {
void *data;
size_t size;
size_t count;
fat_pointer() : data(nullptr), size(0), count(0)
{
}
fat_pointer(void *data_, size_t size_, size_t count_) :
data(data_), size(size_), count(count_)
{
}
bool valid() const {
return data != nullptr;
}
template <typename T>
const T as() {
return static_cast<T>(data);
}
};
int main(int argc, char* argv[])
{
// data can be anything, these two are just for example
const double v1[] = {1.1, 2.2, 3.3, 4.4, 5.5};
const int v2[] = {1, 2, 3, 4, 5};
std::map<std::string, fat_pointer> data;
data.insert(std::pair<std::string, fat_pointer>("V1", fat_pointer((void*)v1, sizeof(v1[0]), sizeof(v1) / sizeof(v1[0]))));
data.insert(std::pair<std::string, fat_pointer>("V2", fat_pointer((void*)v2, sizeof(v2[0]), sizeof(v2) / sizeof(v2[0]))));
auto values = data["V1"];
if (values.valid()) {
std::cout << values.as<double*>()[2] << std::endl;
}
return 0;
}
This approach is super error-prone, does not provide any kind of validation, does not allow to easily count or apply algorithms on the elements, so I really want to get rid of it.
Is there some way to tell the compiler that the value will be an array of an arbitrary type? OR is there any other way I can try to avoid the fat_pointer hack?

If you know the types of your arrays up front, you could use std::variant. You can change your fat_pointer struct to hold a variant of type std::pair<T*, T*> where the first and second members of your pair will hold pointers to the start and one past the end of the array respectively. Then have a templated constructor to capture the type of the array.
std::variant will give you the type safety you want. Plus, now that you're storing the begin and end pointers, you can use them with standard algorithms.
If you're going to treat all the arrays is a uniform way, you don't need separate visitor functions in std::visit. You can get type T in std::pair<T*, T*> using:
using T = std::decay_t<decltype(*arg.first)>;
and then use T.
Here's a example:
#include <iostream>
#include <iomanip>
#include <variant>
#include <vector>
#include <iterator>
#include <algorithm>
using PairVariant = std::variant<std::pair<const int*, const int*>, std::pair<const double*, const double*>>;
struct fat_pointer {
PairVariant mPtrs;
template<typename T>
fat_pointer(T* begin, T* end): mPtrs{std::pair<T*, T*>(begin, end)} {}
};
int main()
{
const double v1[] = {1.1, 2.2, 3.3, 4.4, 5.5};
const int v2[] = {1, 2, 3, 4, 5};
fat_pointer ptr1{v1, std::end(v1)};
fat_pointer ptr2{v2, std::end(v2)};
std::vector<fat_pointer> vec{ptr1, ptr2};
for (auto& v: vec) {
std::visit([] (auto&& arg) {
using T = std::decay_t<decltype(*arg.first)>; //type of T in std::pair<T*, T*>
std::copy (arg.first, arg.second, std::ostream_iterator<T>(std::cout, " "));
}, v.mPtrs);
std::cout << std::endl;
}
return 0;
}
Output:
1.1 2.2 3.3 4.4 5.5
1 2 3 4 5
Live demo.
If you don't know the type of the arrays you're going to store in advance, then I think you will have to use std::any. You can store a pointer to the array and its size, and have a template member function to do a std::any_cast. But if there are arrays of many different types, you will end up testing against those types at runtime and that can be pretty ugly!
struct fat_pointer {
std::any mPtr;
std::size_t mSize;
template<typename T>
fat_pointer(T* begin, T* end): mPtr{begin}, mSize(end-begin) {}
template<typename T>
T AnyCast()
{
if (T* ptr = std::any_cast<T>(&mPtr)) {
return *ptr;
}
return nullptr;
}
};
Here's an example.

Related

Get element-wise mean of vector of vectors of floats in c++

Assuming I have following vector of vectors with the same size:
std::vector<float> a({1, 1, 1});
std::vector<float> b({2, 2, 2});
std::vector<float> c({4, 4, 5});
I would like to get the element-wise mean vector:
std::vector<float> mean({2.333, 2.333, 2.666});
What's the most elegant way to achieve this?
I can write for-loops to do so but was wondering is there better way to do so.
Also note that I would like the solution to scale to any number of vectors (I'm using three vectors for the sake of giving examples)
For element-wise operations, you should be using std::valarray. Primer:
std::valarray<float> a { 1, 1, 1 };
std::valarray<float> b { 2, 2, 2 };
std::valarray<float> c { 4, 4, 5 };
std::valarray<float> mean = (a + b + c) / 3.f;
std::vector<float> v{std::begin(mean), std::end(mean)}
This works in C++11 mode with GCC 7.2.1. Now you haven't specified how you're feeding in the vectors, so what you want isn't clear. If you know in advance how many vectors you'll be dealing with, this should work:
std::valarray<float> foo(std::vector<std::valarray<float>> args) {
assert(args.size() > 0);
// sum MUST be initialized with a size
// and in this case, all sizes must be the same
// otherwise += is undefined behavior
std::valarray<float> sum(args[0].size());
for (auto c : args) {
sum += c;
}
return (sum / (float)args.size());
}
If your inner vectors have always the same size, std::vector seems not like a good choice (it creates unnecessary many small heap allocations and decreases data locality). Better use std::array, or define your own class Vec:
#include <vector>
#include <array>
#include <numeric>
#include <algorithm>
template <typename T, std::size_t N>
struct Vec : std::array<T, N> {
Vec() = default;
explicit Vec(std::array<T, N> const& a): std::array<T, N>(a) {}
static Vec zero() { return Vec(std::array<T, N>{0}); }
Vec operator + (Vec const& rhs) const {
Vec result;
std::transform(std::begin(*this), std::end(*this), std::begin(rhs), std::begin(result), std::plus<T>());
return result;
}
template <typename T2>
Vec operator / (T2 const& rhs) const {
Vec result;
std::transform(std::begin(*this), std::end(*this), std::begin(result), [&](T const& lhs) { return lhs/rhs; });
return result;
}
};
Vec<float, 3> elementwise_mean(std::vector<Vec<float, 3>> vecvec) {
return std::accumulate(std::begin(vecvec), std::end(vecvec), Vec<float, 3>::zero()) / vecvec.size();
}
Or you can be lazy and use a dedicated library like eigen3.
What is the "most elegant way" to achive OP's goal is a matter of opinion, I'm afraid, but surely we can replace most of the explicit for loops with algorithms from the Standard Library.
A vector of vectors may not be the best data structure for every use case and moreover, traversing this object column-wise may not be very cache friendly. However, even if it's mandatory, we can still perform all the needed calculation by traversing the container row-wise, accumulating the sums of each column in a temporary vector and finally computing the averages.
This snippet shows a possible (slightly more general) implementation:
#include <iostream>
#include <vector>
#include <array>
#include <iterator>
#include <stdexcept>
#include <algorithm>
#include <functional>
template<class ReturnType = double, class Container>
auto elementwise_mean(Container const& mat)
{
using MeansType = std::vector<ReturnType>;
using DistType = typename MeansType::iterator::difference_type;
auto it_row = std::begin(mat);
auto n_rows = std::distance(it_row, std::end(mat));
if ( n_rows == 0 )
throw std::runtime_error("The container is empty");
MeansType means(std::begin(*it_row), std::end(*it_row));
const DistType row_size = means.size();
if ( row_size == 0 )
throw std::runtime_error("The first row is empty");
std::for_each(
++it_row, std::end(mat),
[&means, row_size](auto const& row) {
if ( row_size != std::distance(std::begin(row), std::end(row)) )
throw std::runtime_error("A row has a wrong length");
std::transform(
means.begin(), means.end(), std::begin(row),
means.begin(), std::plus()
);
}
);
std::for_each(means.begin(), means.end(), [n_rows](auto & a){ a /= n_rows; });
return means;
}
template<class Container> void print_out(Container const& c);
int main()
{
std::vector<std::vector<double>> test {
{1.0, 1.0, 1.0},
{2.0, 2.0, 2.0},
{4.0, 4.0, 5.0}
};
auto means = elementwise_mean(test);
print_out(means); // --> 2.33333 2.33333 2.66667
std::array<int, 4> test2[2] = {
{{1, 3, -5, 6}},
{{2, 5, 6, -8}},
};
auto means2 = elementwise_mean<float>(test2);
print_out(means2); // --> 1.5 4 0.5 -1
auto means3 = elementwise_mean<int>(test2);
print_out(means3); // --> 1 4 0 -1
}
template<class Container>
void print_out(Container const& c)
{
for ( const auto x : c )
std::cout << ' ' << x;
std::cout << '\n';
}

How to modify the result of a bound member function for std::generate

I am using VS2008 compatible code with Boost 1.60 (no C++ 11). I have a third party library that returns a list-like interface. I want to take the elements of the list and put them in an std::vector. The track_list class has a next method which returns a pointer to a track pointer track**.
I was thinking I could use std::generate to fill a vector the same size as the track_list. I was able to come up with boost::bind(&track_list::next, tracks) which gets me the track** but I am not sure how to add the dereferencing part to get the track* to go into the vector<track*>.
Furthermore, there's actually a specific_track* that I know is safe to cast to from track*. So what I am really looking for is something along the lines of (specific_track*)(*boost::bind(&track_list::next, tracks)) but I am not sure how to construct that syntactically. Am I on the right track? I looked at boost lambdas but the generator function takes no arguments.
Edit: maybe a simpler example might help with clarifying exactly what I'm trying to do.
int** get_ptr_num() { int* i = new int(5); return new int*(i); }
int* get_num() { return new int(5); }
int main() {
std::vector<int*> nums(10);
std::generate(nums.begin(), nums.end(), get_num) // compiles
std::generate(nums.begin(), nums.end(), get_ptr_num) // cannot convert from int** to int*
}
Basically I just want to wrap get_ptr_num in some kind of bind or lambda to do the dereference without creating a separate function to do so.
The second part, the cast, would be something like:
int main() {
std::vector<double*> nums(10);
std::generate(nums.begin(), nums.end(), get_ptr_num) // cannot convert from int** to double*
}
This seems like it would be trivial to do with C++ 11 lambdas, but I can't use C++ 11.
The last part about this being a member function would be something more like this:
class IntGenerator {
public:
int** get_ptr_num() { int* i = new int(5); return new int*(i); }
}
int main() {
IntGenerator int_gen;
std::vector<int*> nums(10);
std::generate(nums.begin(), nums.end(), boost::bind(&IntGenerator::get_ptr_num, int_gen)) // cannot convert from int** to int*
}
You could use a function input iterator:
Live On Coliru
#include <boost/iterator/function_input_iterator.hpp>
#include <vector>
#include <functional>
#include <iostream>
#include <array>
namespace TheAPI {
struct track_list {
std::array<char const*, 6> titles {{ "one", "two", "three", "four", "five", "six" }};
size_t length() const { return titles.size(); }
struct Iterator {
char const* const* raw;
char const* next() { return *raw++; }
};
Iterator get_iterator() const { return {titles.begin()}; };
};
}
int main() {
TheAPI::track_list tl;
auto iter = tl.get_iterator();
auto gen = std::bind(&TheAPI::track_list::Iterator::next, std::ref(iter));
auto first = boost::make_function_input_iterator(gen, 0),
last = boost::make_function_input_iterator(gen, 6);
std::vector<std::string> titles(first, last);
std::copy(titles.begin(), titles.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
}
Of course, if you were thinking of generate, it could be simpler with generate_n:
Live On Coliru
#include <functional>
#include <iterator>
#include <algorithm>
#include <iostream>
#include <array>
namespace TheAPI {
struct track_list {
std::array<char const*, 6> titles {{ "one", "two", "three", "four", "five", "six" }};
size_t length() const { return titles.size(); }
struct Iterator {
char const* const* raw;
char const* next() { return *raw++; }
};
Iterator get_iterator() const { return {titles.begin()}; };
};
}
int main() {
TheAPI::track_list tl;
auto iter = tl.get_iterator();
auto gen = std::bind(&TheAPI::track_list::Iterator::next, std::ref(iter));
std::generate_n(std::ostream_iterator<std::string>{std::cout, "\n"}, tl.length(), gen);
}
Fill a vector using
std::vector<std::string> my_vector;
std::generate_n(back_inserter(my_vector), tl.length(), gen);
Both programs print
one
two
three
four
five
six

How can I define operators so that a array of user-defined types can be transformed into an array of primitive types?

I give the following code to illustrate my question:
#include <vector>
struct Complex
{
int a, b, c;
Complex() : a(3), b(4), c(10) {}
operator int() const { return a+b+c; }
};
int main()
{
Complex abc;
int value = (abc);
Complex def;
def.a = 20;
int value2 = (def);
std::vector<Complex> ar;
ar.push_back(abc);
ar.push_back(def);
std::vector<int> ar2;
ar2.push_back(abc);
ar2.push_back(def);
std::vector<int> ar3;
ar3 = (ar);
}
This won't compile, due to the expression ar3 = (ar). I have declared a conversion operator so that the Complex class can be used in where int is expected. Can I also make it work for assigning an array of Complex objects to an array of int?
I tried to declare a non-member conversion operator for array of Complex, but that's not allowed:
void std::vector<int> operator = (std::vector<Complex> complexArray)
{
std::vector<int> abc;
for(int i=0; i<complexArray.size(); i++)
abc.push_back(complexArray[i]);
return abc;
}
You may consider the range constructor of std::vector.
std::vector<int> ar3(begin(ar), end(ar));
Whenever you want to transform something, the std::transform function might be good to use.
In your case you could do something like
// Create the new vector with the same size as the complex vector
std::vector<int> abc(complexArray.size());
std::transform(std::begin(complexVector), std::end(complexVector),
std::begin(abc),
[](Complex const& complex)
{
int result;
// Code here that converts the complex structure to an integer
// and stores the integer in the variable result
return result;
});
After the std::transform call above (once you complete it with the code to actually do the structure transformation) the vector abc will contain all the converted integers from the Complex structures in the source vector complexVector.
Forget about automatic implicit conversion (at least for the Standard Library containers). But if you are willing to accept an explicit conversion like in the below example
const std::vector<int> vi {1, 2, 3, 4, 5};
const std::vector<double> vd = container_cast(vi);
then the implementation of the container_cast() utility follows. Note that it can cast not only between instantiations of the same template container for different element types (i.e. std::vector<int> to std::vector<double>), but also between different containers (e.g. std::vector to std::list).
#include <iostream>
#include <vector>
#include <list>
template<class SourceContainer>
class ContainerConverter
{
const SourceContainer& s_;
public:
explicit ContainerConverter(const SourceContainer& s) : s_(s) {}
template<class TargetContainer>
operator TargetContainer() const
{
return TargetContainer(s_.begin(), s_.end());
}
};
template<class C>
ContainerConverter<C> container_cast(const C& c)
{
return ContainerConverter<C>(c);
}
template<class C>
void printContainer(const C& c)
{
std::cout << "{ ";
for( auto x : c )
std::cout << x << ' ';
std::cout << "}" << std::endl;
}
int main()
{
const std::vector<double> vd {2.2, 7.7, 5.5, 1.1, -4.4};
printContainer(vd);
const std::vector<int> vi = container_cast(vd);
printContainer(vi);
const std::list<float> lf = container_cast(vd);
printContainer(lf);
return 0;
}

Data controlled programs in c++

Not to sure how to name this question because the problem itself is looking for a construct of which I don´t know its name.
The problem is I am dealing with programs whose control flow depends greatly of data.
For example I created a MIPS simulator which implemented a list of more than 50 instructions, each implemented on its own and everything governed by a huge switch case
switch (function){ //Function is an int, each function (eg SLL) is
case 0: //associated with one
if (state->debug_level > 0){
fprintf(state->debug_out, "SLL\n");
}
step_err = SLL(state, rs, rt, rd, sa);
break;
case 2:
if (state->debug_level > 0){
fprintf(state->debug_out, "SRL\n");
}
step_err = SRL(state, rs, rt, rd, sa);
break;
case 3:
if (state->debug_level > 0){
fprintf(state->debug_out, "SRA\n");
}
//
I have been told that this could have been implemented using function pointers, but to do so what I am looking for is a way of relating data of any kind, say a string to other data, say an integer. I am aware of maps but wouldn't want to push back each pair. I am looking for some sort of array like syntax I think if seen before which might look something similar to this:
¿type? function_codes[]{
0, "SLL";
2, "SRL";
3, "SRA";
...
}
I am not looking for a solution to this problem but a generic approach to introducing quick relationships between data and using this to modify control flow.
EDIT AFTER ANSWERS
What I was actually looking for but I didnt know was indeed maps but in particular its initialization syntax similar to an array (see accepted answer). This used with function pointers did the required job.
As you guessed, function pointers are in fact a good way to do this. Since you specify that you don't want to use a Map, this is how you would implement your integer-based function dispatch using an array of function pointers. Note that since I don't know the type signature of your MIPS functions (SLL, SRL, etc.) I've used dummy placeholder type names.
typedef ret_t (*mips_func)(arg1_t, arg2_t, arg3_t, arg4_t, arg5_t);
mips_func function_codes[] = {
&SLL,
&SRL,
&SRA,
...
};
//...Later, in the part of your code that used to contain the big switch statement
step_err = (*function_codes[function])(state, rs, rt, rd, sa);
The syntax &SLL gets a pointer to the function SLL, which I assume is already in scope because you can call it directly from your switch statement.
Note that this assumes the numeric codes for the functions are a continuous sequence of integers from 0 to [max code value]. If some numeric codes are unused, then you will either need to leave explicit gaps in your array (by placing a NULL pointer in one or more entries) or use std::map<int, mips_func> so that you can use arbitrary non-continuous integer values as keys to functions. Fortunately, using a Map still doesn't require push_backing each element, since C++ now has initializer lists. The same code using a Map would look like this:
typedef ret_t (*mips_func)(arg1_t, arg2_t, arg3_t, arg4_t, arg5_t);
std::map<int, mips_func> function_codes = {
{0, &SLL},
{2, &SRL},
{4, &SRA},
...
};
//Using the Map looks exactly the same, due to its overloaded operator[]
step_err = (*function_codes[function])(state, rs, rt, rd, sa);
For simplify you can use associative containers. If the order is important then use std::map, or std::unordered_map in the other case.
And you can use syntax similar to the desired
std::map<size_t, std::string> codes_map = decltype(codes_map) {
{ 0, "val1" },
{ 1, "val2" }
};
You could group the data as static members w/ the same name across structs, then use templates to access them generically:
struct A { auto call() const { return "((1))"; }; static const char * name; };
struct B { auto call() const { return "{{2}}"; }; static const char * name; };
struct C { auto call() const { return "<<3>>"; }; static const char * name; };
// n.b. these `T...` have: `sizeof(T) == ... == sizeof(empty_struct)`
const char * A::name = "A";
const char * B::name = "B";
const char * C::name = "C";
boost::variant (and the soon to be implemented std::variant) implements a type-safe union, which provides a very clean and efficient way of using these structs as values:
#include <cstdio>
#include <vector>
#include <boost/variant.hpp>
int main()
{
std::vector<boost::variant<A, B, C>> letters{A{}, B{}, C{}, B{}, A{}};
auto visitor = [](auto x) { std::printf("%s(): %s\n", x.name, x.call()); };
for (auto var : letters) { boost::apply_visitor(visitor, var); }
}
Demo
It seems like you have two problems: the flow-control issue (dispatch) and the map issue (an implementation note). I get that the program flow is nonstatic and unknowable at compile-time… but so is the map static? For static maps I get a lot of mileage out of using a traits-ish approach to create a compile-time mapping. Here’s a quick example mapping file suffixes to Objective-C enum constants:
namespace objc {
namespace image {
template <std::size_t N> inline
constexpr std::size_t static_strlen(char const (&)[N]) { return N; }
template <NSBitmapImageFileType t>
struct suffix_t;
#define DEFINE_SUFFIX(endstring, nstype) \
template <> \
struct suffix_t<nstype> { \
static constexpr std::size_t N = static_strlen(endstring); \
static constexpr char const str[N] = endstring; \
static constexpr NSBitmapImageFileType type = nstype; \
};
DEFINE_SUFFIX("tiff", NSTIFFFileType);
DEFINE_SUFFIX("bmp", NSBMPFileType);
DEFINE_SUFFIX("gif", NSGIFFileType);
DEFINE_SUFFIX("jpg", NSJPEGFileType);
DEFINE_SUFFIX("png", NSPNGFileType);
DEFINE_SUFFIX("jp2", NSJPEG2000FileType);
template <NSBitmapImageFileType nstype>
char const* suffix_value = suffix_t<nstype>::str;
}
}
… see how that works? the nice part is that using it has no runtime overhead, which if your map is static, you can use something like that.
For dynamic flow-control and dispatch, function pointers work; that is what happens automatically if you use polymorphic classes and virtual functions but it seems like you have an architecture in place already that may not be amenable to being redone with such high-modernist architectural notions. I like c++11 lambdas as they solve like 90% of my problems in this arena. Perhaps you can elablrate (I will amend my answer)!
If you only have a small number of indices to support, from 0 to 50, you'll get the best performance if you put your function pointers in an array and not a map.
The syntax is also short:
#include <iostream>
#include <functional>
static void f0() {
std::cout << "f0\n";
}
static void f1() {
std::cout << "f1\n";
}
void main()
{
std::function<void()> f[2] = { f0, f1 };
f[0](); // prints "f0"
f[1](); // prints "f1"
}
Or, if you prefer classes over functions:
#include "stdafx.h"
#include <iostream>
class myfunc {
public:
virtual void run() abstract;
virtual ~myfunc() {}
};
class f0 : public myfunc {
public:
virtual void run() {
std::cout << "f0\n";
}
};
class f1 : public myfunc {
public:
virtual void run() {
std::cout << "f1\n";
}
};
void main()
{
myfunc* f[2] = { new f0(), new f1() };
f[0]->run(); // prints "f0"
f[1]->run(); // prints "f1"
for (int i = 0; i < sizeof(f) / sizeof(f[0]); ++i)
delete f[i];
}
Given some definitions
#include <iostream>
#include <iterator>
#include <algorithm>
#include <stdexcept>
#include <map>
using namespace std;
struct state{
int debug_level = 1;
const char* debug_out = "%s";
} s;
// some functions to call
void SLL(state& s, int, int, int, int){
cout << "SLL";
}
void SLR(state& s, int, int, int, int){
cout << "SLR";
}
void SLT(state& s, int, int, int, int){
cout << "SLT";
}
You can use a Map
auto mappedname2fn = map<string, delctype(SLL)*>{
{"SLL", SLL},
{"SLR", SLR}
};
// call a map function
mappedname2fn["SLR"](s, 1, 2, 3, 4);
If you don't want a map you can use a pre-sorted array for a binary search
Here's a binary search of an array of name, function pairs
template<typename P, int N, typename ...T>
auto callFn(P(&a)[N], string val, T&&... params){
auto it = lower_bound(a, a+N, make_pair(val, nullptr),
[](auto& p1, auto& p2){return p1.first < p2.first;});
if(it==(a+N) || val<it->first) throw logic_error("not found");
return it->second(forward<T>(params)...);
}
So you can set up an array and use that:-
// array sorted in alphabetical order for binary search to work
pair<string, decltype(SLL)*> name2fn[] = {
{"SLL", SLL},
{"SLR", SLR},
{"SLT", SLT}
};
void callFn(string name, state& s, int a, int b, int c, int d){
try{
callFn(name2fn, name, s, a, b, c, d);
}
catch(exception& e){
cout << e.what();
}
}
// call it
callFn("SLL", s, 1, 2, 3, 4);

std::string not working with std::set

I'm doing a programming question from C++ Primer Plus which asks me to make a template
function that returns the number of unique elements in an array. I don't understand why
line 13 causes an error while compiling as to my knowledge, a std::string behaves like an array.
This is my code:
#include <iostream>
#include <set>
template <typename T>
int reduce(T ar[], int n);
int main()
{
long test[] = {1, 2, 1, 3, 3, 4, 1};
std::string testStr = "testing";
std::cout << reduce(test, 6) << std::endl;
std::cout << reduce(testStr, 7) << std::endl;
std::cin.get();
return 0;
}
template <typename T>
int reduce(T ar[], int n)
{
std::set<T> test;
for(int i = 0; i < n; i++)
{
test.insert(ar[i]);
}
return test.size();
}
Following up my immediate response that std::string is not an array, this is the way a C++ person might accomplish the task you're looking for.
#include <iterator>
#include <iostream>
#include <set>
// instead of taking an array and length, just take where you want to start and where
// you want to stop.
template <typename TForwardIterator>
int reduce(TForwardIterator iter, TForwardIterator end)
{
// This is hideous syntax to get the type of object the iterator is describing.
// For std::string, it is char...for T*, it is T.
// I apologize for C++, I'm not sure there is a better way to do this.
typedef typename std::iterator_traits<TForwardIterator>::value_type value_type;
std::set<value_type> set;
// instead of forcing the objects to be an array type, use iterators!
for (; iter != end; ++iter)
set.insert(*iter);
return set.size();
}
int main()
{
long test[] = {1, 2, 1, 3, 3, 4, 1};
std::string testStr = "testing";
// begin() and end() are iterators you'll find on all the container types
std::cout << reduce(testStr.begin(), testStr.end()) << std::endl;
// pointers are iterators, too!
std::cout << reduce(test, test + 7) << std::endl;
return 0;
}
The answer is quite simple: std::string is not an array.
It behaves like an array so far as you can access the elements using the [] operator, but it is simply not the same data type as char[]. As a matter of fact the standard doesn't even guarantee that it's stored like an array (meaning continously). T[] will only match to array of, not objects which can be used arraylike.
In order to solve this you have several options
you can call reduce(teststr.c_str(), 7), since c_str() will return an chararray with the contents of the string.
You could rewrite reduce as template <typename T, typename U> int reduce(U ar, int n) and call it as reduce<long>(test, 6) and reduce<char>(testStr, 7). The second template parameter is necessary, since there is no unified way to get from the container to the element (except in c++0x/using compiler extensions).
If you are using c++0x you can use decltype to get from a container to the contained element: template <typename T>int reduce(T ar, int n) and std::set<decltype(ar[0])> test; (rest of the code remains unchanged, and somehow I seem to have trouble with code block sections so just these two lines here.
Of course in c++ one would typically write such a function in terms of iterators (see Travis Gockels answer), since that's simply a more flexible and better supported way.
You may be confusing std::strings with built-in character arrays. std::strings are not arrays, though they behave similarly to arrays (the class has an overloaded [] operator) and contain arrays (which you can access through c_str()).
If you replace line 10 with
char testStr[] = "testing";
Your program will compile and run.
Or, you could try something like:
#include <iostream>
#include <set>
template <typename T>
int reduce(const T* ar, int n);
int main()
{
long test[] = {1, 2, 1, 3, 3, 4, 1};
std::string testStr = "testing";
std::cout << reduce(test, 7) << std::endl;
std::cout << reduce(testStr.c_str(), testStr.size()) << std::endl;
std::cin.get();
return 0;
}
template <typename T>
int reduce (const T* ar, int n)
{
std::set<T> test;
for(int i = 0; i < n; i++)
{
test.insert(ar[i]);
}
return test.size();
}