2016-02-01 26 views
7

Chcę utworzyć konstruktor klasy, używając dowolnego typu integralnego, ale rozróżniając podpisany i unsigned. Nie chcę, aby był to szablon na samej klasie. Poniższe nie działa. Visual Studio mówi tylko, że żadne argumenty nie będą pasować.Tworzenie konstruktora variadic dla zmiennych podpisanych i niepodpisanych przy użyciu enable_if

class Thing{ 
public: 
    template<typename Integral> 
    Thing(
     typename std::enable_if< 
      std::is_integral<Integral>::value && 
      !std::is_same<Integral,bool>::value && 
      std::is_signed<Integral>::value 
      ,Integral 
     >::type num 
    ){ 
     //constructor using signed variable as input 
    } 
    template<typename Integral> 
    Thing(
     typename std::enable_if< 
      std::is_integral<Integral>::value && 
      !std::is_same<Integral,bool>::value && 
      !std::is_signed<Integral>::value//notice this is different 
      ,Integral 
     >::type num 
    ){ 
     //constructor using unsigned variable as input 
    } 
}; 
+1

To nie działa? Co to robi? :) – erip

+0

Brak słowa kluczowego "public" mówi co najmniej o pierwszym błędzie, który dostanę próbując kodu powyżej ... – skypjack

Odpowiedz

5

Musimy przenieść SFINAE do szablonu. Jeśli używamy

class Thing{ 
public: 
    template<typename Integral, typename std::enable_if< 
      std::is_integral<Integral>::value && 
      !std::is_same<Integral,bool>::value && 
      std::is_signed<Integral>::value 
      ,Integral>::type* = nullptr> // will fail if type does not exist 
    Thing(Integral i) 
//  ^use Integral type here 
    { 
     std::cout << "signed\n"; 
    } 
    template<typename Integral, typename std::enable_if< 
      std::is_integral<Integral>::value && 
      !std::is_same<Integral,bool>::value && 
      !std::is_signed<Integral>::value//notice this is different 
      ,Integral>::type* = nullptr> 
    Thing(Integral i) 
    { 
     std::cout << "unsigned\n"; 
    } 
}; 

int main() 
{ 
    int a = 10; 
    Thing b(a); 
    unsigned int c = 10; 
    Thing d(c); 
} 

Dostajemy

signed 
unsigned 

Live Example

miałem też zrobić konstruktorów public jak były private domyślnie.

3

Problem polega na tym, że typ pojawia się w non-deduced context, więc kompilator nie może wyprowadzić go z czymś takim std::is_integral<Integral>::value. Spróbuj to zamiast:

#include <iostream> 
#include <type_traits> 

class Thing{ 
public: 
    template<typename Integral> 
    Thing(Integral num, 
     typename std::enable_if< 
      std::is_integral<Integral>::value && 
      !std::is_same<Integral,bool>::value && 
      std::is_signed<Integral>::value 
      ,Integral 
     >::type* = nullptr 
    ){ 
     std::cout << "signed\n"; 
     //constructor using signed variable as input 
    } 

    template<typename Integral> 
    Thing(Integral num, 
     typename std::enable_if< 
      std::is_integral<Integral>::value && 
      !std::is_same<Integral,bool>::value && 
      !std::is_signed<Integral>::value//notice this is different 
      ,Integral 
     >::type* = nullptr 
    ){ 
     std::cout << "unsigned\n"; 
     //constructor using unsigned variable as input 
    } 
}; 

int main() 
{ 
    int x{}; 
    unsigned int y{}; 
    Thing thing1(x); 
    Thing thing2(y); 
} 

Live on Coliru

marginesie: dokonać konstruktorzy public gdyż w przeciwnym razie nie można utworzyć wystąpienia swoich obiektów.

+0

Podstępnie unikasz wskazywania, że ​​OP musi również sprawić, że córki będą "publiczne" :-) – AndyG

+0

@AndyG Zapomniałem o tym wspomnieć, ale zrobiłem je 'public' w moim kodzie;) – vsoftco

+0

Osobiście wolałbym wstawić' enable_if' w szablonie args: 'template :: wartość) && (! std :: is_same :: wartość) && (std :: is_signed :: wartość), int> :: type = 0> Thing (T _in) 'ale to wszystko to samo – AndyG