2013-07-24 5 views
35

folgenden Code vor:Select Klasse Konstruktor enable_if

#include <iostream> 
#include <type_traits> 

template <typename T> 
struct A { 
    int val = 0; 

    template <class = typename std::enable_if<T::value>::type> 
    A(int n) : val(n) {}; 
    A(...) { } 

    /* ... */ 
}; 

struct YES { constexpr static bool value = true; }; 
struct NO { constexpr static bool value = false; }; 

int main() { 
    A<YES> y(10); 
    A<NO> n; 
    std::cout << "YES: " << y.val << std::endl 
       << "NO: " << n.val << std::endl; 
} 

Ich möchte selektiv Konstruktor definieren A :: A (int) nur für einige Arten mit enable_if. Für alle anderen Typen gibt es den Standardkonstruktor A :: A (...), der der Standardfall für den Compiler sein sollte, wenn die Substitution fehlschlägt. Aber das macht Sinn für mich Compiler (gcc Version 4.9.0 20130714) noch beschwert

sfinae.cpp: In instantiation of 'struct A': sfinae.cpp:19:11:
required from here sfinae.cpp:9:5: error: no type named 'type' in
'struct std::enable_if'
A(int n) : val(n) {};

Ist so etwas möglich für Konstruktor? Ist das mit anderen Konstruktoren möglich (copy-constructor und move-constructor)?

+0

Darf man ein bisschen Hilfsarbeiterklasse sein? –

Antwort

31

Ich denke, das kann nicht mit einem einzigen Standard-Template-Parameter arbeiten, da sein Wert gelöst werden muss, wenn die Klassenvorlage instanziiert wird.

Wir müssen die Ersetzung an den Punkt der Instanziierung der Konstruktortemplates verschieben. Eine Möglichkeit besteht darin, den Vorlagenparameter auf T zu setzen und dem Konstruktor einen zusätzlichen Dummy-Parameter hinzuzufügen:

+0

bessere Erklärung als meine: D –

+0

@JoelFalcou Ihr arbeitet tatsächlich. [Dies ist nicht immer noch] (http://coliru.stacked-crooked.com/view?id=15f3b29d734e0b4f765cf6fddc19896d-fcf98f666e0b68774061981371328429) – Rapptz

+0

@Rapptz Mein schlechtes ist, weil es in einem Standard-Template-Parameter verwendet wird. Es muss in der Konstruktorsignatur sein. Ich werde es reparieren. – jrok

8

Normalerweise erfolgt ein anonymes notleidenden Argument:

A(int n, typename std::enable_if<T::value>::type* = 0) : val(n) {}; 

Sie nicht Template-Parameter aus der Klasse SFINAE outen Methoden verwenden können. SO ein Weg ist, ein Dummy-Typ int ersetzt hinzuzufügen:

siehe: http://ideone.com/2Gnyzj

#include <iostream> 
#include <type_traits> 

template <typename T> 
struct A { 
    int val = 0; 

    template<typename Integer 
      ,typename = typename std::enable_if<T::value && sizeof(Integer)>::type 
      > 
    A(Integer n) : val(n) {}; 

    A(...) {} 
    /* ... */ 
}; 

struct YES { constexpr static bool value = true; }; 
struct NO { constexpr static bool value = false; }; 

int main() { 
    A<YES> y(10); 
    A<NO> n; 
    std::cout << "YES: " << y.val << std::endl 
       << "NO: " << n.val << std::endl; 
} 

Dies funktioniert, weil Sie Mitglied Template-Parameter verwenden, um den Konstruktor SFINAE, aber der Test ist immer wahr, so dass es doesn 't verschmutzen Ihre Schecks

+3

Das gibt immer noch den gleichen Fehler, und ich hatte den Eindruck, dass die OP-Methode die üblichste war. – chris

+0

@chris Es ist tatsächlich. – Rapptz

+0

Es ist in C++ 11. Ich habe gerade die std :: enable_if bemerkt. –