Template std::enable_if

0

Hej. Mam pewną klasę, chciałbym żeby klasa ta działała tylko z liczba całkowitymi/zmiennoprzecinkowymi.
Przedtem wykorzystywałem zwykłego static asserta:

#include <type_traits>
#include <cstdio>
#include <string>

template<class _T>
class Class {
public:
	Class() {
		static_assert(std::is_arithmetic<_T>::value, "Error");
	};
};

int main() {
	Class<int> class1;
	Class<float> class2;
	Class<std::string> class3;

	getchar();
	return 0;
}

Teraz robię to tak:

template<class _T, typename std::enable_if<std::is_arithmetic<_T>::value>::type* = 0>
class Class {
public:
	Class() {};
};

int main() {
	Class<int> class1;
	Class<float> class2;
	Class<std::string> class3;

	getchar();
	return 0;
}

Działać działa ale czy ktoś mógłby powiedzieć czy jest to zrobione poprawnie?

4

Trochę naookoło robisz, bo deklarujesz "non-type template parameter"

template<class _T, typename = typename std::enable_if<std::is_arithmetic<_T>::value>::type>

Powinno działać, a jeśli masz C++14 i wyżej:

template<class _T, typename = std::enable_if_t<std::is_arithmetic<_T>::value>>

Swoją drogą, użycie _T to UB:

N4606, §2.10[lex.name]/3 napisał(a)

In addition, some identifiers are reserved for use by C++ implementations and shall not be used otherwise; no diagnostic is required.
— Each identifier that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.

0
kq napisał(a):

Trochę naookoło robisz, bo deklarujesz "non-type template parameter"

template<class _T, typename = typename std::enable_if<std::is_arithmetic<_T>::value>::type>

Powinno działać, a jeśli masz C++14 i wyżej:

template<class _T, typename = std::enable_if_t<std::is_arithmetic<_T>::value>>

Swoją drogą, użycie _T to UB:

N4606, §2.10[lex.name]/3 napisał(a)

In addition, some identifiers are reserved for use by C++ implementations and shall not be used otherwise; no diagnostic is required.
— Each identifier that contains a double underscore __ or begins with an underscore followed by an uppercase letter is reserved to the implementation for any use.

Ok, dzięki :D
I jeszcze jedno pytanie bo nie mogę sobie poradzić, mianowicie jak zapisać definicję metody z tej klasy?

#include <type_traits>
#include <cstdio>
#include <string>

template <typename type, typename = std::enable_if_t<std::is_arithmetic<type>::value>>
class Class {
public:
	Class() {};

	void Method();
};

template <typename type, typename = std::enable_if_t<std::is_arithmetic<type>::value>>
void Class<type>::Method() {

}

int main() {
	Class<int> class1;
	class1.Method();

	getchar();
	return 0;
}
3

Ja bym to chyba zrobił tak:

#include <type_traits>

// Template alias zawsze jest fajne.
template <typename T>
using EnableIfInt =
  std::enable_if_t<std::is_arithmetic<T>::value>;

// Glowny szablon, zostanie wybrany jezeli ten nizej nie zostanie.
template <typename T, typename Enable = void>
class Class {
  static_assert(sizeof(T) == 0, "Nie wolno");
};

// Czesciowa specjalizacja szablonu glownego.
template <typename T>
class Class<T, EnableIfInt<T>> {
public:
  Class() {}
  void Method();
};
 
template <typename T>
void Class<T, EnableIfInt<T>>::Method() {
}
 
int main() {
  Class<int> class1;
  // Class<int [2]> class2; // Tu bedzie static_assert.
  
  class1.Method();
}

http://ideone.com/Un291M
http://ideone.com/xQFgUB

Na to jest kilka metod i sam nie wiem, która jest najlepsza...

0
Endrju napisał(a):

Ja bym to chyba zrobił tak:

...

http://ideone.com/Un291M
http://ideone.com/xQFgUB

Na to jest kilka metod i sam nie wiem, która jest najlepsza...

Wielkie dzięki :D
I mam jeszcze jedno pytanie, próbuję przeciążyć operator << ale nie za bardzo mi to wychodzi, co robię źle?

Severity	Code	Description	Project	File	Line	Suppression State
Error	C2039	'<<': is not a member of 'Class<T,enable_if<_Test,void>::type>'	Injector	F:\Old shits\Framework v2\Projects\Injector\Main.cpp	414	
#include <type_traits>
#include <iostream>

// Template alias zawsze jest fajne.
template <typename T>
using EnableIfInt =
std::enable_if_t<std::is_arithmetic<T>::value>;

// Glowny szablon, zostanie wybrany jezeli ten nizej nie zostanie.
template <typename T, typename Enable = void>
class Class {
	static_assert(sizeof(T) == 0, "Nie wolno");
};

// Czesciowa specjalizacja szablonu glownego.
template <typename T>
class Class<T, EnableIfInt<T>> {
public:
	Class() {}
	void Method();

	int Something = 99;

	friend std::ostream& operator<<(std::ostream& Stream, const Class<T>& Klasa);
};

template <typename T>
void Class<T, EnableIfInt<T>>::Method() {

}

template <typename T>
std::ostream& Class<T, EnableIfInt<T>>::operator<<(std::ostream& Stream, const Class<T>& Klasa) {
	Stream << Something;
	return Stream;
}

int main() {
	Class<int> class1;
	// Class<int [2]> class2; // Tu bedzie static_assert.

	class1.Method();
}
1

deklaracja:

template <typename T>
std::ostream& operator<<(std::ostream& Stream, const Class<T, EnableIfInt<T>>& Klasa);

deklaracja friend:

friend std::ostream& operator<< <>(std::ostream& Stream, const Class& Klasa);

definicja:

template <typename T>
std::ostream& operator<<(std::ostream& Stream, const Class<T, EnableIfInt<T>>& Klasa) {
	Stream << Klasa.Something;
	return Stream;
}

Działanie:
http://melpon.org/wandbox/permlink/hbIhax3ncOFKl7lH

1 użytkowników online, w tym zalogowanych: 0, gości: 1