SFINAE aktifkan_jika konstruktor eksplisit

Saya mencoba beralih antara konstruktor konversi eksplisit dan implisit melalui enable_if.

Kode saya saat ini terlihat seperti

#include <type_traits>
#include <cstdint>

enum class enabled {};

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

template <std::intmax_t A> struct SStruct
{
    static constexpr std::intmax_t a = A;
};

template <typename T> struct SCheckEnable : std::integral_constant<bool, T::a == 0>
{
};

template <typename U, typename T> class CClass
{
    public:
        template <typename T2, enable_if_t<SCheckEnable<U>::value, enabled>...> constexpr CClass(T2 v) : val(v) {};
        template <typename T2, disable_if_t<SCheckEnable<U>::value, enabled>...> explicit constexpr CClass(T2 v) : val(v) {};

    private:
        T val;
};

int main()
{
    CClass<SStruct<0>, double> a = 1;                             // should use implicit constructor
    CClass<SStruct<1>, double> b = CClass<SStruct<1>, double>(1); // should use explicit constructor
}

true di enable_ifs bergantung pada parameter templat U

Jika saya mencoba mengkompilasi contoh minimal ini dengan g++ 4.9.1 dan --std=c++11 diaktifkan, saya mendapatkan kesalahan berikut

sfinae.cpp: In substitution of ‘template<bool B, class T> using disable_if_t = typename std::enable_if<(! B), T>::type [with bool B = true; T = enabled]’:
sfinae.cpp:13:52:   required from here
sfinae.cpp:7:95: error: no type named ‘type’ in ‘struct std::enable_if<false, enabled>’
 template <bool B, typename T = void> using disable_if_t = typename std::enable_if<!B, T>::type;
                                                                                               ^
sfinae.cpp:19:68: error: prototype for ‘constexpr CClass<U, T>::CClass(T2)’ does not match any in class ‘CClass<U, T>’
 template <typename U, typename T> template <typename T2> constexpr CClass<U, T>::CClass(T2 v) : val(v)
                                                                    ^
sfinae.cpp:13:77: error: candidates are: template<class U, class T> template<class T2, int ...<anonymous> > constexpr CClass<U, T>::CClass(T2)
   template <typename T2, disable_if_t<true, enabled>...> explicit constexpr CClass(T2 v);
                                                                             ^
sfinae.cpp:12:67: error:                 template<class U, class T> template<class T2, enabled ...<anonymous> > constexpr CClass<U, T>::CClass(T2)
   template <typename T2, enable_if_t<true, enabled>...> constexpr CClass(T2 v);
                                                                   ^

Adakah yang tahu cara memilih antara konstruksi eksplisit dan implisit berdasarkan parameter U di sini?


person Uroc327    schedule 15.11.2014    source sumber
comment
Saya bisa membuat ini berfungsi dengan baik. Tidak yakin apa perbedaan antara kode Anda dan kode saya.   -  person Rapptz    schedule 15.11.2014
comment
Mungkinkah constexpr menjadi penyebabnya?   -  person Uroc327    schedule 15.11.2014
comment
Tidak. Ini seharusnya tidak berpengaruh pada SFINAE. Mungkin ada hubungannya dengan mendefinisikannya di luar kelas dan cara Anda melakukannya, tetapi saya tidak sepenuhnya yakin.   -  person Rapptz    schedule 15.11.2014
comment
Jika true di sini bukan kode sebenarnya tetapi bergantung pada parameter templat, maka kode Anda akan berfungsi.   -  person 0x499602D2    schedule 15.11.2014
comment
@Rapptz Mendefinisikan ctor segera menghapus semua kesalahan kecuali yang pertama (no type named 'type'...) dalam contoh minimal saya di sana.   -  person Uroc327    schedule 15.11.2014
comment
@ 0x499602D2 Saya menggunakan sesuatu seperti std::integral_constant<bool, U::a == 0>::value sebagai bool untuk enable_ifs, dengan U::a adalah static constexpr std::intmax_t a = ...;   -  person Uroc327    schedule 15.11.2014
comment
Agar SFINAE terjadi, konstruksi harus memuat parameter templat dari templat langsung.   -  person 0x499602D2    schedule 15.11.2014


Jawaban (1)


Menggunakan

template <class...> struct null_v : std::integral_constant<int, 0> {};

dan mendefinisikan konstruktor sebagai

template <typename T2,
          long = null_v<enable_if_t<SCheckEnable<U>::value, T2>>::value>
constexpr CClass(T2 v) : val(v) {};

template <typename T2,
          int = null_v<disable_if_t<SCheckEnable<U>::value, T2>>::value>
explicit constexpr CClass(T2 v) : val(v) {};

Membuat argumen bergantung dan benar-benar dipakai. Demo.

[pengurangan sementara]/8:

Jika substitusi menghasilkan tipe atau ekspresi yang tidak valid, pengurangan tipe akan gagal. Tipe atau ekspresi yang tidak valid adalah tipe atau ekspresi yang bentuknya salah jika ditulis menggunakan argumen pengganti.

Dalam kasus Anda, kesalahan terjadi di luar substitusi apa pun, jadi hal itu tidak menyebabkan kegagalan pengurangan melainkan membuat kode Anda salah bentuk.

person Columbo    schedule 15.11.2014
comment
Mengkompilasi dan berfungsi sebagaimana mestinya... Di manakah sebenarnya letak perbedaan antara percobaan saya dan solusi Anda? - person Uroc327; 15.11.2014
comment
Jika saya memahami komentar @ 0x499602D2 dengan benar, aktifkan_if perlu 'memproses' sesuatu dengan T2, karena ini adalah parameter templat untuk mengaktifkan atau menonaktifkan fungsi tertentu. Apakah saya melakukannya dengan benar? :) - person Uroc327; 15.11.2014
comment
@ Uroc327 Mengedit jawabannya. - person Columbo; 15.11.2014