Implicit construction and templated class

Viewed 85

The question is simple, how you use implicit construction/conversion for templated class in C++14.

Comment on the code below, A is what is expected, automatic construction/conversion of const char* to A.

B is a templated class, I do not have the expected behavior of A and to get a "similar" behavior I need to specify the type against which I'll, in this case test compare equal (note the explicit const T* and not const B<T>&). This is problematic because I would expect an automatic conversion from const T* to B<T> as specified in B's constructor.

C is a templated class and exposes the behavior of A. It is a better solution to the problem than B is. The problem, it requires the use of a template trick, see below. The goal would be to ditch this trick. The trick solves the problem, can we make it work without it ?

Note: the code below is compiling on "recent" versions of g++/clang++/msvc and icc without error.

Code below accessible here: https://godbolt.org/z/W9x5Kcqrn

#include <cassert>
#include <iostream>

struct A {
    A(const char *aze) { std::cout << "A ctor\n"; }
};

template <typename T>
struct B {
    B(const T *aze) { std::cout << "B<T> ctor\n"; }
};

template <typename T>
struct C {
    C(const T *aze) { std::cout << "C<T> ctor\n"; }
};

////////////////////////////////

bool operator==(const A &, const A &) {
    std::cout << "A==A\n";
    return true;
}

////

template <typename T>
bool operator==(const B<T> &, const T *) { // I dont want const T* here, I already have a constructor that can do it for me
    std::cout << "B<T>==T*\n";
    return true;
}

template <typename T>
bool operator==(const T *, const B<T> &) { // I dont want const T* here, I already have a constructor that can do it for me
    std::cout << "T*==B<T>\n";
    return true;
}

////

// I would like to ditch this TypeIdentity trickery

template <class T>
struct TypeIdentity {
    using type = T;
};

template <class T>
using TypeIdentity_t = typename TypeIdentity<T>::type;

template <typename T>
bool operator==(const C<T> &, const TypeIdentity_t<C<T>> &) {
    std::cout << "C<T>==C<tT>\n";
    return true;
}

template <typename T>
bool operator==(const TypeIdentity_t<C<T>> &, const C<T> &) {
    std::cout << "C<tT>==C<T>\n";
    return true;
}

template <typename T>
bool operator==(const C<T> &, const C<T> &) {
    std::cout << "C<T>==C<T>\n";
    return true;
}

////////////////////////////////

int main() {
    // Works as expected, conversion of "xrb" to A and then operator==(const A &,
    // const A &) called
    // Prints: A ctor  A ctor  A==A
    assert(A{"aze"} == "xrb");

    // Works as expected, operator==(const B<T> &, const T *) called
    // Prints: B<T> ctor  B<T>==T*
    assert(B<char>{"aze"} == "xrb");
    // Works as expected, operator==(const T *, const B<T> &) called
    // Prints: B<T> ctor  T*==B<T>
    assert("aze" == B<char>{"xrb"});

    // Work as expected with TypeIdentity_t, does not compile without it
    assert(C<char>{"aze"} == "xrb");
    assert("xrb" == C<char>{"aze"});
    assert(C<const char>{"aze"} == "xrb");

    // Works as expected, operator==(const C<T> &, const C<T> &) called
    // Prints: C<T> ctor  C<T> ctor  C<T>==C<T>
    assert(C<char>{"aze"} == C<char>{"xrb"});
}

Looking forward to your answers, Thanks

0 Answers
Related