I'm fairly new to C++. I've searched extensively but I couldn't make it work.
I've defined a custom type called vec_t:
class FloatType {
private:
float value;
public:
FloatType() : value(0.0f) {}
FloatType(float v) : value(v) {}
//operator float() { return value; }
//operator float() { return value; }
//explicit operator const float* () { return &value; }
//operator float* () const { return &value; }
//operator const float* () { return &value; }
//operator const float() { return (const float)value; }
//operator const float*() { return &value; }
};
typedef FloatType vec_t;
I've also created a function which takes a const float * as its only argument:
void Create(const float* vColor = NULL);
void Create(const float* vColor) {
//...
}
Now, when calling the function like so:
vec_t a = { 2.5f };
vec_t* b = &a;
Create(b);
Visual Studio Community 2019 (v142) is complaining:
argument of type "vec_t *" is incompatible with parameter of type "const float *"
Now, casting it to const float * on the spot gets it done:
Create((const float *)b);
But, my goal is to have an implicit casting operator to implicitly convert from my type to const float *, but no matter my efforts, I can not seem to have it right.
All operator comments were my attempts and they all have valid syntax, but they don't make the problem go away.
What am I not understanding?
I want to be able to handle this from within the FloatType class itself, and to my knowledge, an implicit casting operator is the way to do so.
Don't guide me to another approach, this is purely for practice and exercise.
The problem is that while vec_t is a class type that can have conversion operators defined, vec_t * is a primitive type (a pointer), and no user-defined conversions apply to it.
Some possible solutions:
Don't pass around pointers to vec_t, pass them by value instead. If necessary, use std::move to avoid potentially expensive copies. This boils down to just Create(a). john's answer explains this in more detail.
Dereference the pointer, as in Create(*b), to allow the compiler to find your user-defined conversions.
Add a float * data() member function to vec_t, just like std::vector, and call that to get at the underlying data: Create(b->data())
Don't use your own vector type and just use std::array<float, N> for statically-sized vectors and std::vector<float> for dynamically sized ones. This is likely the best solution. To get a pointer to the raw data, use vec.data(). (Again, take advantage of these types' value semantics to get memory safety. Move / copy them, don't use raw pointers.)
If you want something really ugly that you shouldn't do: Create(b->operator float *()).
Your vec_t type is not a pointer, so you should not be using a pointer as the argument when calling Create():
class FloatType
{
private:
float value;
public:
...
operator const float* () const { return &value; }
// const here ^^^^^
};
typedef FloatType vec_t;
vec_t a = { 2.5f };
Create(a);
For some reason, you introduced the pointer b, that's the main reason your code doesn't work.
Also, you should have an extra const on your conversion operator, as I've indicated above.
This question already has answers here:
How to convert "pointer to pointer type" to const?
(2 answers)
Closed 9 years ago.
I have the very simple code in c++. When I compile under Visual studio, the error happens.
#include <stdint.h>
#include <time.h>
void func1(const uint8_t* data)
{
}
void func2(const uint8_t** data)
{
}
int main()
{
uint8_t* data1 = NULL;
uint8_t** data2 = NULL;
func1(data1);//OK
func2(data2);//error C2664: cannot convert argument 1 from 'uint8_t **' to 'const uint8_t **'
}
the full error meesage is:
error C2664: 'void func2(const uint8_t **)' : cannot convert argument 1 from 'uint8_t **' to 'const uint8_t **'
Usualy you cannot convert const XXX to XXX, but from XXX to const XXX should be OK, Why this error happens here?
but from XXX to const XXX should be OK
No, this isn't okay in this specific instance. Consider:
int const x = 10; // implementation stores to read-only memory
// implementation crashes on writes to read-only memory
void foo(int const **ptr) {
*ptr = &x;
}
int main() {
int *p;
foo(&p);
*p = 12; // crash
}
If this were legal it would assign a 'pointer to const' value to a 'pointer to non-const' object, and therefore enable dangerous writing to constant objects.
For a conversion to const to be okay const must be added at every level in the type above where the lowest const is added (except the very top).
For example it's not okay to convert int ****** to int ***const***, but it is okay to convert it to int ***const*const*const*. This also applies to volatile: you can convert int ****** to int ***volatile*const*const* but not int ***volatile***
This rule in the type system protects us from mistakenly treating const objects as non-const, or volatile objects as non-volatile, and if we really want to make this mistake then we have to use const_cast.
foo(const_cast<int const **>(&p));
*p = 12; // crash
With const cast the program is well formed and the compiler happily produces an executable that exhibits undefined behavior. (live example)
Fixing foo() to allow it to take a pointer to non-const:
void foo(int const * const *ptr) {
*ptr = &x; // error, can't modify *ptr
}
foo(&p); // conversion works fine
prevents foo() from writing a 'pointer to const' value into a 'pointer to non-const' object. (live example)
You probably got the idea that XXX to const XXX is okay because the most common case of this, i.e. with single level pointers: int * -> int const *, is okay and also obeys the above conversion rule. const at the very top level doesn't matter because changes to the parameter itself won't escape the function.
When you use const to pointer of pointer you need to use uint8_t const* const*
#include <stdint.h>
#include <time.h>
void func1(const uint8_t* data) {
}
void func2( uint8_t const* const* data ) {
}
int main() {
uint8_t* data1 = NULL;
uint8_t** data2 = NULL;
func1(data1);//OK
func2(data2);
}
Here are your two options, this...
void func1(const uint8_t* data)
{
}
void func2(const uint8_t** data)
{
}
int main()
{
const uint8_t* data1 = NULL;
const uint8_t** data2 = NULL;
func1(data1);
func2(data2);
}
Or this...
void func1(uint8_t* data)
{
}
void func2(uint8_t** data)
{
}
int main()
{
uint8_t* data1 = NULL;
uint8_t** data2 = NULL;
func1(data1);
func2(data2);
}
I have a unsigned char*. Typically this points to a chunk of data, but in some cases, the pointer IS the data, ie. casting a int value to the unsigned char* pointer (unsigned char* intData = (unsigned char*)myInteger;), and vice versa.
However, I need to do this with a float value, and it keeps giving me conversion errors.
unsigned char* data;
float myFloat = (float)data;
How can I do this?
bit_cast:
template <class Dest, class Source>
inline Dest bit_cast(Source const &source) {
static_assert(sizeof(Dest)==sizeof(Source), "size of destination and source objects must be equal");
static_assert(std::is_trivially_copyable<Dest>::value, "destination type must be trivially copyable.");
static_assert(std::is_trivially_copyable<Source>::value, "source type must be trivially copyable");
Dest dest;
std::memcpy(&dest, &source, sizeof(dest));
return dest;
}
Usage:
char *c = nullptr;
float f = bit_cast<float>(c);
c = bit_cast<char *>(f);
The only correct way to use a given variable to store other data is to copy the data byte-wise:
template <typename T>
void store(unsigned char * & p, T const & val)
{
static_assert(sizeof(unsigned char *) >= sizeof(T));
char const * q = reinterpret_cast<char const *>(&val);
std::copy(q, q + sizeof(T), reinterpret_cast<char *>(&p));
}
Usage:
unsigned char * p;
store(p, 1.5);
store(p, 12UL);
The matching retrieval function:
template <typename T>
T load(unsigned char * const & p)
{
static_assert(sizeof(unsigned char *) >= sizeof(T));
T val;
char const * q = reinterpret_cast<char const *>(&p);
std::copy(q, q + sizeof(T), reinterpret_cast<char *>(&val));
return val;
}
Usage:
auto f = load<float>(p);
If your compiler supports it (GCC does) then use a union. This is undefined behavior according to the C++ standard.
union {
unsigned char* p;
float f;
} pun;
pun.p = data;
float myFloat = pun.f;
This works if sizeof(unsigned char *) == sizeof(float). If pointers are larger than floats then you have to rethink your strategy.
See wikipedia article on type punning and in particular the section on use of a union.
GCC allows type punning using a union as long as you use the union directly and not typecasting to a union... see this IBM discussion on type-pun problems for correct and incorrect ways of using GCC for type punning.
Also see wikipedia's article on strong and weak typing and a well researched article on type punning and strict aliasing.
unsigned char* data;
float myFloat = *(float*)data;
On my Linux (and OS X) machines, the iconv() function has this prototype:
size_t iconv (iconv_t, char **inbuf...
while on FreeBSD it looks like this:
size_t iconv (iconv_t, const char **inbuf...
I would like my C++ code to build on both platforms. With C compilers, passing a char** for a const char** parameter (or vice versa) typically emits a mere warning; however in C++ it's a fatal error. So if I pass a char**, it won't compile on BSD, and if I pass a const char** it won't compile on Linux / OS X. How can I write code that compiles on both, without resorting to trying to detect the platform?
One (failed) idea I had was to provide a local prototype that overrides any provided by the header:
void myfunc(void) {
size_t iconv (iconv_t, char **inbuf);
iconv(foo, ptr);
}
This fails because iconv needs C linkage, and you cannot put extern "C" within a function (why not?)
The best working idea I've come up with is to cast the function pointer itself:
typedef void (*func_t)(iconv_t, const char **);
((func_t)(iconv))(foo, ptr);
but this has the potential to mask other, more serious errors.
If what you want is just to turn a blind eye to some const issues, then you can use a conversion which blurs the distinction, i.e. makes char** and const char** interoperable:
template<class T>
class sloppy {};
// convert between T** and const T**
template<class T>
class sloppy<T**>
{
T** t;
public:
sloppy(T** mt) : t(mt) {}
sloppy(const T** mt) : t(const_cast<T**>(mt)) {}
operator T** () const { return t; }
operator const T** () const { return const_cast<const T**>(t); }
};
Then later in the program:
iconv(c, sloppy<char**>(&in) ,&inlen, &out,&outlen);
sloppy() takes a char** or a const char* and converts it to a char** or a const char*, whatever the second parameter of iconv demands.
UPDATE: changed to use const_cast and call sloppy not a as cast.
You can disambiguate between the two declarations by inspecting the signature of the declared function. Here's a basic example of the templates required to inspect the parameter type. This could easily be generalized (or you could use Boost's function traits), but this is sufficient to demonstrate a solution for your specific problem:
#include <iostream>
#include <stddef.h>
#include <type_traits>
// I've declared this just so the example is portable:
struct iconv_t { };
// use_const<decltype(&iconv)>::value will be 'true' if the function is
// declared as taking a char const**, otherwise ::value will be false.
template <typename>
struct use_const;
template <>
struct use_const<size_t(*)(iconv_t, char**, size_t*, char**, size_t*)>
{
enum { value = false };
};
template <>
struct use_const<size_t(*)(iconv_t, char const**, size_t*, char**, size_t*)>
{
enum { value = true };
};
Here's an example that demonstrates the behavior:
size_t iconv(iconv_t, char**, size_t*, char**, size_t*);
size_t iconv_const(iconv_t, char const**, size_t*, char**, size_t*);
int main()
{
using std::cout;
using std::endl;
cout << "iconv: " << use_const<decltype(&iconv) >::value << endl;
cout << "iconv_const: " << use_const<decltype(&iconv_const)>::value << endl;
}
Once you can detect the qualification of the parameter type, you can write two wrapper functions that call iconv: one that calls iconv with a char const** argument and one that calls iconv with a char** argument.
Because function template specialization should be avoided, we use a class template to do the specialization. Note that we also make each of the invokers a function template, to ensure that only the specialization we use is instantiated. If the compiler tries to generate code for the wrong specialization, you'll get errors.
We then wrap usage of these with a call_iconv to make calling this as simple as calling iconv directly. The following is a general pattern showing how this can be written:
template <bool UseConst>
struct iconv_invoker
{
template <typename T>
static size_t invoke(T const&, /* arguments */) { /* etc. */ }
};
template <>
struct iconv_invoker<true>
{
template <typename T>
static size_t invoke(T const&, /* arguments */) { /* etc. */ }
};
size_t call_iconv(/* arguments */)
{
return iconv_invoker<
use_const<decltype(&iconv)>::value
>::invoke(&iconv, /* arguments */);
}
(This latter logic could be cleaned up and generalized; I've tried to make each piece of it explicit to hopefully make it clearer how it works.)
You can use the following:
template <typename T>
size_t iconv (iconv_t i, const T inbuf)
{
return iconv(i, const_cast<T>(inbuf));
}
void myfunc(void) {
const char** ptr = // ...
iconv(foo, ptr);
}
You can pass const char** and on Linux/OSX it will go through the template function
and on FreeBSD it will go directly to iconv.
Drawback: it will allow calls like iconv(foo, 2.5) which will put compiler in infinite recurrence.
#ifdef __linux__
... // linux code goes here.
#elif __FreeBSD__
... // FreeBSD code goes here.
#endif
Here you have ids of all operating systems. For me it doesn't have any point to try doing something what depends on operating system without checking this system. It's like buying green trousers but without looking at them.
You've indicated that using your own wrapper function is acceptable. You also seem to be willing to live with warnings.
So, instead of writing your wrapper in C++, write it in C, where you'll only get a warning on some systems:
// my_iconv.h
#if __cpluscplus
extern "C" {
#endif
size_t my_iconv( iconv_t cd, char **restrict inbuf, ?* etc... */);
#if __cpluscplus
}
#endif
// my_iconv.c
#include <iconv.h>
#include "my_iconv.h"
size_t my_iconv( iconv_t cd, char **inbuf, ?* etc... */)
{
return iconv( cd,
inbuf /* will generate a warning on FreeBSD */,
/* etc... */
);
}
How about
static void Test(char **)
{
}
int main(void)
{
const char *t="foo";
Test(const_cast<char**>(&t));
return 0;
}
EDIT: of course, the "without detecting the platform" is a bit of a problem. Oops :-(
EDIT 2: ok, improved version, maybe?
static void Test(char **)
{
}
struct Foo
{
const char **t;
operator char**() { return const_cast<char**>(t); }
operator const char**() { return t; }
Foo(const char* s) : t(&s) { }
};
int main(void)
{
Test(Foo("foo"));
return 0;
}
What about:
#include <cstddef>
using std::size_t;
// test harness, these definitions aren't part of the solution
#ifdef CONST_ICONV
// other parameters removed for tediousness
size_t iconv(const char **inbuf) { return 0; }
#else
// other parameters removed for tediousness
size_t iconv(char **inbuf) { return 0; }
#endif
// solution
template <typename T>
size_t myconv_helper(size_t (*system_iconv)(T **), char **inbuf) {
return system_iconv((T**)inbuf); // sledgehammer cast
}
size_t myconv(char **inbuf) {
return myconv_helper(iconv, inbuf);
}
// usage
int main() {
char *foo = 0;
myconv(&foo);
}
I think this violates strict aliasing in C++03, but not in C++11 because in C++11 const char** and char** are so-called "similar types". You aren't going to avoid that violation of strict aliasing other than by creating a const char*, set it equal to *foo, call iconv with a pointer to the temporary, then copy the result back to *foo after a const_cast:
template <typename T>
size_t myconv_helper(size_t (*system_iconv)(T **), char **inbuf) {
T *tmpbuf;
tmpbuf = *inbuf;
size_t result = system_iconv(&tmpbuf);
*inbuf = const_cast<char*>(tmpbuf);
return result;
}
This is safe from the POV of const-correctness, because all iconv does with inbuf is increment the pointer stored in it. So we're "casting away const" from a pointer derived from a pointer that was non-const when we first saw it.
We could also write an overload of myconv and myconv_helper that take const char **inbuf and messes things about in the other direction, so that the caller has the choice whether to pass in a const char** or a char**. Which arguably iconv should have given to the caller in the first place in C++, but of course the interface is just copied from C where there's no function overloading.
Update: now I see that it is possible to handle it in C++ without autotools, yet I'm leaving the autoconf solution for people looking for it.
What you're looking for is iconv.m4 which is installed by gettext package.
AFAICS it's just:
AM_ICONV
in configure.ac, and it should detect the correct prototype.
Then, in the code you use:
#ifdef ICONV_CONST
// const char**
#else
// char**
#endif
I am late to this party but still, here is my solution:
// This is here because some compilers (Sun CC) think that there is a
// difference if the typedefs are not in an extern "C" block.
extern "C"
{
//! SUSv3 iconv() type.
typedef size_t (& iconv_func_type_1) (iconv_t cd, char * * inbuf,
size_t * inbytesleft, char * * outbuf, size_t * outbytesleft);
//! GNU iconv() type.
typedef size_t (& iconv_func_type_2) (iconv_t cd, const char * * inbuf,
size_t * inbytesleft, char * * outbuf, size_t * outbytesleft);
} // extern "C"
//...
size_t
call_iconv (iconv_func_type_1 iconv_func, char * * inbuf,
size_t * inbytesleft, char * * outbuf, size_t * outbytesleft)
{
return iconv_func (handle, inbuf, inbytesleft, outbuf, outbytesleft);
}
size_t
call_iconv (iconv_func_type_2 iconv_func, char * * inbuf,
size_t * inbytesleft, char * * outbuf, size_t * outbytesleft)
{
return iconv_func (handle, const_cast<const char * *>(inbuf),
inbytesleft, outbuf, outbytesleft);
}
size_t
do_iconv (char * * inbuf, size_t * inbytesleft, char * * outbuf,
size_t * outbytesleft)
{
return call_iconv (iconv, inbuf, inbytesleft, outbuf, outbytesleft);
}
I have a class which hold an array "float ** table". Now I want to have member function to return it, but don't want it to be modified outside of the class. So I did this:
class sometable
{
public:
...
void updateTable(......);
float **getTable() const {return table;}
private:
...
float **table;
}
This compiles OK when I call getTable with a constant object. Now I tried to
make it safer by declaring getTable as "const float **getTable()". I got
the following compilation error:
Error:
Cannot return float**const from a function that should return const float**.
Why? How can I avoid table to be modified out side of the class?
Declare your method like this:
float const* const* getTable() const {return table;}
or
const float* const* getTable() const {return table;}
if you prefer.
You can't assign a float** to a float const** because it would allows to modify a const object:
float const pi = 3.141592693;
float* ptr;
float const** p = &ptr; // example of assigning a float** to a float const**, you can't do that
*p = π // in fact assigning &pi to ptr
*ptr = 3; // PI Indiana Bill?
C and C++ rules differ about what is allowed.
C++ rule is that when you add a const before a star, you have to add a const before each following one.
C rule is that you can only add a const before the last star.
In both languages, you can remove a const only before the last star.
You could declare your method as
const float * const * const getTable() const {return table;}
but even this (the outermost const - next to the function name) would not prevent the client to try to delete it.
You could return reference instead, but the best would be to use an std::vector for table and return const ref to it - unless using a C style array is a must
Though you can clearly type the syntax just like that, I find it much more readable to define some typedefs for multiple-dimension arrays.
struct M {
typedef double* t_array;
typedef const double t_carray;
typedef t_array* t_matrix;
typedef const t_carray* t_cmatrix;
t_matrix values_;
t_cmatrix values() const { return values_; }
t_matrix values() { return values_; }
};