SFINAE Enable_if ตัวสร้างที่ชัดเจน

ฉันกำลังพยายามสลับระหว่างตัวสร้างการแปลงที่ชัดเจนและโดยนัยผ่าน enable_if

รหัสของฉันในปัจจุบันดูเหมือนว่า

#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 ใน enable_ifs ขึ้นอยู่กับพารามิเตอร์เทมเพลต U

หากฉันพยายามคอมไพล์ตัวอย่างขั้นต่ำนี้โดยเปิดใช้งาน g++ 4.9.1 และ --std=c++11 ฉันได้รับข้อผิดพลาดต่อไปนี้

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);
                                                                   ^

มีความคิดใดที่จะเลือกระหว่างโครงสร้างที่ชัดเจนและโดยนัยตามพารามิเตอร์ U ที่นี่


person Uroc327    schedule 15.11.2014    source แหล่งที่มา
comment
ฉันสามารถสิ่งนี้เพื่อให้ทำงานได้ดี ไม่แน่ใจว่ารหัสของคุณกับของฉันแตกต่างกันอย่างไร   -  person Rapptz    schedule 15.11.2014
comment
constexpr อาจเป็นสาเหตุของสิ่งนี้หรือไม่   -  person Uroc327    schedule 15.11.2014
comment
ไม่ มันไม่ควรมีผลกระทบใดๆ ต่อ SFINAE อาจเกี่ยวข้องกับการกำหนดนอกชั้นเรียนและวิธีการที่คุณทำ แต่ฉันไม่มั่นใจทั้งหมด   -  person Rapptz    schedule 15.11.2014
comment
หาก true ในที่นี้ไม่ใช่โค้ดจริง แต่ขึ้นอยู่กับพารามิเตอร์เทมเพลต โค้ดของคุณควรใช้งานได้   -  person 0x499602D2    schedule 15.11.2014
comment
@Rapptz การกำหนด ctor จะลบข้อผิดพลาดทั้งหมดทันทียกเว้นอันแรก (no type named 'type'...) ในตัวอย่างขั้นต่ำของฉันที่นั่น   -  person Uroc327    schedule 15.11.2014
comment
@ 0x499602D2 ฉันใช้บางอย่างเช่น std::integral_constant<bool, U::a == 0>::value เป็นบูลสำหรับ enable_ifs โดยที่ U::a คือ static constexpr std::intmax_t a = ...;   -  person Uroc327    schedule 15.11.2014
comment
เพื่อให้ SFINAE เกิดขึ้น การสร้างจำเป็นต้องมีพารามิเตอร์เทมเพลตจากเทมเพลต ทันที   -  person 0x499602D2    schedule 15.11.2014


คำตอบ (1)


ใช้

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

และกำหนดตัวสร้างเป็น

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) {};

ทำให้การโต้แย้งขึ้นอยู่กับและสร้างอินสแตนซ์จริง สาธิต

[อุณหภูมิหัก]/8:

หาก การทดแทน ส่งผลให้ประเภทหรือนิพจน์ไม่ถูกต้อง การหักประเภทจะล้มเหลว ประเภทหรือนิพจน์ที่ไม่ถูกต้องคือประเภทหรือนิพจน์ที่จะมีรูปแบบไม่ถูกต้องหากเขียน โดยใช้อาร์กิวเมนต์ที่ถูกแทนที่

ในกรณีของคุณ เกิดข้อผิดพลาดนอกเหนือจากการทดแทนใดๆ ดังนั้นจึงไม่ทำให้เกิดความล้มเหลวในการหักเงิน แต่จะทำให้โค้ดของคุณมีรูปแบบไม่ถูกต้อง

person Columbo    schedule 15.11.2014
comment
คอมไพล์และทำงานตามที่ควรจะเป็น... อะไรคือความแตกต่างระหว่างความพยายามของฉันกับวิธีแก้ปัญหาของคุณ? - person Uroc327; 15.11.2014
comment
หากฉันเข้าใจความคิดเห็น @ 0x499602D2 อย่างถูกต้อง Enable_if จำเป็นต้อง 'ประมวลผล' บางอย่างด้วย T2 เนื่องจากนี่คือพารามิเตอร์เทมเพลตสำหรับฟังก์ชันเฉพาะเพื่อเปิดหรือปิดใช้งาน ฉันเข้าใจถูกแล้วใช่ไหม? :) - person Uroc327; 15.11.2014
comment
@ Uroc327 แก้ไขคำตอบ - person Columbo; 15.11.2014