Uroc327
Uroc327

Reputation: 1429

Implicit template constructor gets ignored

In a c++11 project I have some structs like those:

#include <type_traits>

template <bool B, class T = void> using disable_if_t = typename std::enable_if<!(B), T>::type;

enum class disable {};

template <int A> struct StructA
{
    using sa = StructA<A>;

    static constexpr int a = A;
    static constexpr int b = 1;
};

template <typename SA, int B> struct StructB
{
    using sa = typename SA::sa;

    static constexpr int a = sa::a;
    static constexpr int b = B;
};

template <typename SB, typename = int> struct disable_first : std::integral_constant<bool, SB::a == 0 && SB::b == 1>
{
};

template <typename> struct disable_second : std::false_type
{
};

template <typename, typename> class StructC;
template <typename SB, typename T2> struct disable_second<StructC<SB, T2>> : std::true_type
{
};

template <typename SB, typename T> struct StructC
{
    template <typename T2, disable_if_t<disable_first<SB, T2>{} || disable_second<T2>{}, disable>...> explicit StructC(T2 v) noexcept;
    template <typename SB2, typename T2> StructC(const StructC<SB2, T2>& v) noexcept;
    template <typename SB2, typename T2> StructC(StructC<SB2, T2>&& v) noexcept;
};

template <typename T, typename T2> void Func(StructC<StructA<1>, T2> b);

int main()
{
    StructC<StructB<StructA<1>, 1>, int> x(40);
    Func<float>(x);

    return 0;
}

Now I basically have two quesions:

  1. Can the StructC(const StructC<SB2, T2>& s) constructor used as copy-constructor (same counts for StructC(StructC<SB2, T2>&& s) for move constructing)

  2. How can I say the compiler, that it's totally OK to call Func with StructB<StructA<1>, 1> and int although it requires StructA<1> and float without explicitly calling the constructor? The constructor of StructC is totally capable of converting between those.

Edit 1: provide an example which fails correctly.

Upvotes: 0

Views: 344

Answers (1)

T.C.
T.C.

Reputation: 137345

Can the StructC(const StructC<S1, T1>& s) constructor used as copy-constructor (same counts for StructC(StructC<S1, T1>&& s) for move constructing)

A copy or move constructor cannot be a template. StructC will have an implicitly declared copy constructor and an implicitly declared move constructor. When you copy or move the object, the implicitly declared constructors will participate in overload resolution with your constructor templates; if they are equally as good (which appears to be the case in your code), the implicitly declared non-template constructor will be preferred.

Note that copy elision (including (named) return value optimization) cannot be performed if overload resolution for the "copy/move" operation selects your constructor template rather than an actual copy/move constructor. This may impact performance.

How can I say the compiler, that it's totally OK to call Func with StructA<1, 2, 3> and float although it requires StructB<4, 5> and double without explicitly call the constructor? The constructor of StructC is totally capable of converting between those.

Your current constructor template already defines an implicit conversion from every kind of StructC to every other kind of StructC. Your code should compile once a default constructor is added to StructC.

Upvotes: 2

Related Questions