2

Is it possible to have a traits in order to convert, let's say, char* to const char* in order to use it further to call functions having const char* parameters using a char* variable?

I have this (the context is large, I've simplified, sorry for the ugly code):

#include <iostream>
using namespace std;
#include <stdio.h>
#include <string.h>
#include <typeinfo>

template<typename T, typename U, std::enable_if_t<std::is_same<T, U>::value, int> = 0>
T convert_type(U _in)
{
    return _in;
}

template<typename T, typename U, std::enable_if_t<std::is_same<T, std::add_lvalue_reference_t<U>>::value, int> = 0>
T& convert_type(U& _in)
{
    return _in;
}

template<typename T, typename U, std::enable_if_t<std::is_same<T, std::add_lvalue_reference_t<std::add_const_t<U>>>::value, int> = 0>
T& convert_type(U& _in)
{
    return _in;
}

template<typename T, typename U, std::enable_if_t<std::is_same<T, std::add_pointer_t<U>>::value, int> = 0>
T convert_type(U& _in)
{
    return std::addressof(_in);
}

int main() {

    char* c = new char[sizeof "test"];
    strcpy(c, "test");

    const char * cc = convert_type<const char *, char *>(c); // here not compilable yet due to lack of the right convert_type specialization

    cout << c;

    delete[] c;
    return 0;
}

Just to clarify, I embed SpiderMonkey to script Illustrator API. This made me write pretty complicated code, but I have checked and I know the conversion traits above are in use for various function calls. I've added them here just to see the approach and to clarify the need of adding another that recognizes a type and returns the needed type. All your comments are correct generally, but not in my context. I might have a convoluted code, but I have simplified it as much as I could.

sample code here

As far as it concerns me, the question is not yet answered and I couldn't find a solution. I put the question this way: how to write a traits method to match char* against const char*, which is char const*, actually, when I check in msvc with typeid a type or variable declared as const char*?

mike
  • 408
  • 5
  • 18
  • 1
    How about just casting to const char*? – Christopher Schneider Jun 13 '16 at 16:31
  • 2
    What's wrong with `static_cast`? – Barry Jun 13 '16 at 16:31
  • 1
    `char*` to `const char*` happens implicitly. – Arunmu Jun 13 '16 at 16:32
  • You shouldn't need to. You can just assign `c` to `cc`. It's the other direction that becomes the problem. – Edward Strange Jun 13 '16 at 16:34
  • Can you clarify what you mean? After all, `char*` is implicitly convertible to `const char*` – milleniumbug Jun 13 '16 at 16:39
  • Of course, but the context is larger, if I put it here anybody will complain that I've been too detailed, so I have narrowed it as much as I could. See [here](http://stackoverflow.com/questions/35104226/c-variadic-template-arguments-method-to-pass-to-a-method-without-variadic-argu) and [here](http://stackoverflow.com/questions/36461452/c-function-caller-wrapper-using-variadic-pack-types-expansion) for details. – mike Jun 13 '16 at 16:39
  • 2
    I don't think `char * c = "test";` is valid C++ – KABoissonneault Jun 13 '16 at 16:49
  • 1
    @mike As for your edit, you have probably _simplified_ your real code too much. Try to provide a [MCVE] that clearly shows what your problem actually is. – πάντα ῥεῖ Jun 13 '16 at 16:50
  • @KABoissonneault Well, it works under MSVC. It is not so standard, but please correct it if you want. – mike Jun 13 '16 at 16:50
  • @mike _"Well, it works under MSVC"_ MSVC often allows non-standard syntax. But as every other up to date compiler does, it should leave you whith an appropriate warning. – πάντα ῥεῖ Jun 13 '16 at 16:52
  • @mike It only works in MSVC because your warning level is too low and/or you don't treat warnings as errors. Let your compiler help you when it can – KABoissonneault Jun 13 '16 at 16:53
  • @πάντα ῥεῖ No, it does not, but this is not the matter... I know MSVC is always off standards... – mike Jun 13 '16 at 16:54
  • OK, please advise what is the right level and the correct code for that. – mike Jun 13 '16 at 16:59
  • So, I can't add the plethora of classes and templates here, I just need a `convert_type` overload to be able to compile the commented out code, `const char * cc = convert_type(c);`. – mike Jun 13 '16 at 17:05
  • @mike So again, what's wrong implementing `convert_type()` just providing `c` using a simple `return c;` statement in that function? – πάντα ῥεῖ Jun 13 '16 at 17:10
  • How to make this compileable? See [here](https://ideone.com/rO035H). – mike Jun 13 '16 at 17:18

4 Answers4

3

Is it possible to have a traits in order to convert, let's say, char* to const char* in order to use it further to call functions having const char* parameters using a char* variable?

As pointed out in the comments, a traits conversion isn't needed at all, since a char* pointer can be used equally as a const char* pointer at any time, since the conversion is implicit (same for any other type than char).


Note that the line in your main() function

char * c = "test";

isn't valid c++ syntax. "test" actually is a const char [5] type and you can't assign that to other than a const char* pointer legally.
At least any attempt to write a value to that pointer will be undefined behavior.

Most c++11 compliant compilers will issue a warning on that statement.


As for your edited example now

char* c = new char[sizeof "test"];
strcpy(c, "test");

//const char * cc = convert_type<const char *, char *>(c);

there's no need for using the convert_type() traits function, you can simply write (as also mentioned in the comments):

const char * cc = c;
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
0

Just use assignment:

const char* cc = c;

(with the caveat that char* c = "test" is ill-formed)

To be more explicit, which is never a bad thing, you can use one of the standard C++ casts:

auto cc = static_cast<const char*>(c);

Your first three convert_type() overloads are basically useless - all of them can be trivially substituted by simply using =. And = actually handles more cases than your convert_type() too.

The fourth overload should be substituted in favor of just & (or directly using std::addressof), there's really no need to hide that you're taking the address. Certainly T* x = &y is a lot easier to understand the meaning of than T* x = convert_type<T*>(y).

Barry
  • 286,269
  • 29
  • 621
  • 977
0

(To 'defend' OP: yes, I also thought of simply adding const, since const const T is the same as const T, but, on the other hand, I can think of situations, where you have to pass a type trait that does nothing else but this.) How about:

// ordinary way w/o type aliases
template<typename T>
struct const_qualify
{
    typedef const T type;
};

// do this if you have type aliases
template<typename T>
using const_qualify_t = const T;

Note that, if you just want to compare types, we have now remove_const<> / remove_cv<>: http://en.cppreference.com/w/cpp/types/remove_cv

EDIT: actually, we also have std::add_const<>.

lorro
  • 10,687
  • 23
  • 36
  • 1
    Thank you for giving me some credit that I am not simply fool to write a useless piece of code to make a complicated assignment when an easy and clear way already exists. You sense it right, it seems I need a new `convert_type` overload or specialization able by its `condition` to detect T is `const` and return the right thing. I'm still looking for it or for a way to rewrite all `convert` functions to achieve the goal. – mike Jun 14 '16 at 05:36
  • Yes, I want to compare types, but I can't write some method similar to `convert_type` above using `remove_const` or `remove_ct`. – mike Jun 25 '16 at 16:48
  • Is that different from `std::add_const` and `std::add_const_t`? – user2023370 Apr 02 '17 at 23:43
  • @user2023370: it's the same, above is just an implementation of it. – lorro Apr 03 '17 at 07:58
0

Eventually, I've made it, using this post:

template<typename T> struct remove_all_const : std::remove_const<T> {};

template<typename T> struct remove_all_const<T*> {
    typedef typename remove_all_const<T>::type *type;
};

template<typename T> struct remove_all_const<T * const> {
    typedef typename remove_all_const<T>::type *type;
};


template<typename T, typename U, std::enable_if_t<std::is_same<typename remove_all_const<T>::type, typename remove_all_const<U>::type>::value, int> = 0>
T convert_type(U& _in)
{
    return _in;
}

A big Thank! to that post solver!

Community
  • 1
  • 1
mike
  • 408
  • 5
  • 18