extending std::basic_string::append

Hi,

I'm trying to design a buffer class, which contains a block of unsigned char. The std::basic_string<unsigned char> seems exactly what I need, but here's the problem, when I append data to the buffer, for convenience, I need the append function can take both char* and unsigned char*, for example:

1
2
3
4
5
6
7
8
9
10
11
typedef unsigned char uchar;
typedef basic_string<uchar> buffer;

char* str = "abc";
uchar* ustr = (uchar*)"abc";

int main() {
	buffer b;
	b.append(str, 3); // compile error: append() cannot convert char* to uchar*
	b.append(ustr, 3);
}


Then I derived the basic_string, and extend the append function:
1
2
3
4
5
6
struct buffer : public basic_string<uchar> {
	buffer& append(const char* s, int size) {
		append((uchar*)s, size);
		return *this;
	}
};

but it also doesn't work, compile error: append cannot convert uchar* to const char*
seems after the deriving, the other append() functions from basic_string are gone
why is that and how to fix?

Thanks.
1
2
3
4
5
6
struct buffer : public basic_string<uchar> {
	buffer& append(const char* s, int size) {
		append((uchar*)s, size);
		return *this;
	}
};
Aren't your signednesses backwards? The function should take a const unsigned char * and pass a const signed char *.
I think the problem is that when it finds a append function in the base class it will not go on to look for it in the subclasses. You can fix this by using using.
1
2
3
4
5
6
7
struct buffer : public basic_string<uchar> {
	buffer& append(const char* s, int size) {
		append((uchar*)s, size);
		return *this;
	}
	using basic_string<uchar>::append;
};

using basic_string<uchar>::append;
this works, just learned a new little trick.

Thanks guys.
got a problem when calling append() in sequence:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
typedef unsigned char uchar;

// typedef basic_string<uchar> buffer;
struct buffer : public basic_string<uchar> {
	buffer& append(const char* s, int size) {
		append((uchar*)s, size);
		return *this;
	}
	using basic_string<uchar>::append;
};



char* str = "abc";
uchar* ustr = (uchar*)"abc";

int main() {
	buffer b;

	b.append(ustr, 3)  // the append returns basic_string<uchar>&, so it won't support append(char*) anymore
	.append(str, 3) // compile err..
	.append(ustr, 3);

}

what I can come up with is a wrapper function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct buffer : public basic_string<uchar> {
	template<class T>
	buffer& add(const T* s, int size) {
		append((uchar*)s, size);
		return *this;
	}
};

int main() {
	buffer b;

	b.add(ustr, 3)
	.add(str, 3)
	.add(ustr, 3);
}


any better solution? I think it's better not to have a new function, because I will have to write some other add() wrappers for the other append() functions.
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <string>
using namespace std;

typedef basic_string<char> buffer;
typedef unsigned char uchar;

int main ()
{
    char* str="hello";
    uchar* ustr=(uchar*)"world";
    buffer buf;

    buf.append((char*)ustr).append(str);
}


This is a slight variation on your first code that just forces the conversion between uchar* and char*
Last edited on
hi, theranga,

there's plenty of unsigned strings, so I would have to write (uchar*) everywhere, so I'm looking for a convenient way.
ok

1
2
3
4
5
6
7
8
9
10
11
12
13
struct buffer : public basic_string<uchar> {
	buffer& append(const char* s, int sz) {
		append((uchar*)s, sz);
		return *this;
	}
	buffer& append(const uchar* s,int sz)
	{
	    basic_string<uchar> str (s,sz);
	    append(str);
	    return (*this);
    }
	using basic_string<uchar>::append;
};
as long as you leave one declaration of append 'unoverloaded' and maybe do something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct buffer : protected basic_string<uchar> {
	buffer& append(const char* s, int sz) {
		append((uchar*)s, sz);
		return *this;
	}
	buffer& append(const uchar* s,int sz)
	{
	    basic_string<uchar> str (s,sz);
	    append(str);
	    return (*this);
    }
	using basic_string<uchar>::append;
	using basic_string<uchar>::assign;
	using basic_string<uchar>::at;
	...
};


you can prevent access to functions which don't return buffer&
it seems hard to do it perfect, I'm gonna use the force conversion..

Thanks.
std::basic_string is not polymorphic, you're not supposed to derive from it to start with. But even if it were,

design a buffer class, which contains a block of unsigned char

This design pattern is called "composition". The buffer class should have vector<unsigned char> or basic_string<unsigned char> or some other 'block of unsigned char' as a data member.
Topic archived. No new replies allowed.