Reputation: 1429
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:
Can the StructC(const StructC<SB2, T2>& s)
constructor used as copy-constructor (same counts for StructC(StructC<SB2, T2>&& s)
for move constructing)
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
Reputation: 137345
Can the
StructC(const StructC<S1, T1>& s)
constructor used as copy-constructor (same counts forStructC(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>
andfloat
although it requiresStructB<4, 5>
anddouble
without explicitly call the constructor? The constructor ofStructC
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