-
Overloading Issue
Hi,
I've got a weird little problem. I've got a class that requires a pointer to a memory buffer, along with its size, at construction.
Code:
template<typename E>
class buffer
{
E *m_ptr;
std::size_t m_size;
public:
buffer(E *ptr, std::size_t size) : m_ptr(ptr), m_size(size) {}
For convenience and a bit of safety, I also offer this constructor:
Code:
template<int N>
buffer(E (&ar)[N]) : m_ptr(ar), m_size(N) {}
This way, you can construct it like this and it will infer the correct size:
Code:
char ar[5] = { 1, 2, 3, 4, 5 };
buffer<char> b(ar);
This works very nicely.
Now, I also want to provide a constructor that takes an array reference AND a size, and uses the supplied size only if it doesn't exceed the array size:
Code:
template<int N>
buffer(E (&ar)[N], std::size_t size) : m_ptr(ar), m_size(size < N ? size : N) {}
}
However, when I want to prove this works:
Code:
char ar[5] = { 1, 2, 3, 4, 5 };
buffer<char> b(ar, 7);
... it actually chooses the pointer constructor.
Thinking about it, it makes sense: the non-template is generally ordered before templates in overload resolution. However, I don't want it there.
So, does anyone have any idea how I could get the array+size constructor to be used in this situation without destroying the other use cases?
-
Without doing any leg-work :) do you think boost::is_array<> could be utilized in some fashion?
gg
-
Hmm, perhaps something like this?
Code:
#include <iostream>
#include <cstddef>
template <typename E>
class buffer {
E *m_ptr;
std::size_t m_size;
public:
template <typename T>
buffer ( T ptr, std::size_t size )
: m_ptr ( ptr ), m_size ( size )
{
std::cout<<"Pointer constructor\n";
}
template <int N>
buffer ( E (&ar)[N], std::size_t size )
: m_ptr ( ar ), m_size ( size < N ? size : N )
{
std::cout<<"Array constructor w/size\n";
}
template <int N>
buffer ( E (&ar)[N] )
: m_ptr ( ar ), m_size ( N )
{
std::cout<<"Array constructor\n";
}
};
int main()
{
char ar1[5] = { 1, 2, 3, 4, 5 };
buffer<char> b1(ar1);
char ar2[5] = { 1, 2, 3, 4, 5 };
buffer<char> b2(ar2, 7);
char *p = new char[10];
buffer<char> b3(p, 10);
}
Making the constructor a template function alters the overload order, and because the constructor is assigning a pointer to a pointer, a mismatched type for the first argument will result in a compile-time error because it's assigning X type to a pointer to E without a cast.
-
Good idea, Prelude. I had thought about making the pointer constructor a template, but somehow suffered from mental block and couldn't find this simple way.
Codeplug, enable_if would indeed be another option.
Thanks, I'll try these out.
-
>> Hmm, perhaps something like this?
ingenious. =)
>> E (&ar)[N]
just curious...but what is the benefit of passing a reference to an array?
-
You cannot pass the array directly, as it would decay to a pointer in the parameter list. Only by passing it by reference can you preserve the array and, more importantly, enforce extent checking.
-
you're right. I tried to instantiate the following function, but got an error unless I specified the template argument explicitly:
Code:
template <unsigned Size>
void
foo(int array[Size])
{
}
//...
foo(array); // error
foo<1024>(array); // fine
thanks.
-
Prelude, your suggestion worked. Thanks a lot.