μ¬μ©λ²μ μ΄ν΄νκΈ° μν΄ κ°λ¨ν μμ λ₯Ό μ»μΌλ €κ³ ν©λλ€ std::enable_if
. μ΄ λ΅λ³μ μ½μ ν κ°λ¨ν μλ₯Ό μ μνκΈ°κ° λ무 μ΄λ ΅μ§ μμμΌνλ€κ³ μκ°νμ΅λλ€. std::enable_if
λ λ©€λ² ν¨μ μ€μμ μ ννκ³ κ·Έμ€ νλλ§ μ¬μ©ν μ μλλ‘ μ¬μ©νκ³ μΆμ΅λλ€ .
λΆννλ, λ€μμ gcc 4.7λ‘ μ»΄νμΌλμ§ μμΌλ©° λͺ μκ° λμ λ Έλ ₯ν νμ λν¬λ€μκ² λ΄ μ€μκ° λ¬΄μμΈμ§ λ¬»κ³ μλ€.
#include <utility>
#include <iostream>
template< class T >
class Y {
public:
template < typename = typename std::enable_if< true >::type >
T foo() {
return 10;
}
template < typename = typename std::enable_if< false >::type >
T foo() {
return 10;
}
};
int main() {
Y< double > y;
std::cout << y.foo() << std::endl;
}
gccλ λ€μκ³Ό κ°μ λ¬Έμ λ₯Όλ³΄κ³ ν©λλ€.
% LANG=C make CXXFLAGS="-std=c++0x" enable_if
g++ -std=c++0x enable_if.cpp -o enable_if
enable_if.cpp:12:65: error: `type' in `struct std::enable_if<false>' does not name a type
enable_if.cpp:13:15: error: `template<class T> template<class> T Y::foo()' cannot be overloaded
enable_if.cpp:9:15: error: with `template<class T> template<class> T Y::foo()'
μ g ++κ° λ λ²μ§Έ λ©€λ² ν¨μμ λν μλͺ»λ μΈμ€ν΄μ€λ₯Ό μμ νμ§ μμ΅λκΉ? νμ€μ λ°λ₯΄λ©΄ std::enable_if< bool, T = void >::type
λΆμΈ ν
νλ¦Ώ λ§€κ° λ³μκ° true μΈ κ²½μ°μλ§ μ‘΄μ¬ν©λλ€. κ·Έλ¬λ μ g ++λ μ΄κ²μ SFINAEλ‘ κ°μ£Όνμ§ μμ΅λκΉ? μ€λ²λ‘λ μ€λ₯ λ©μμ§λ g ++μ΄ λ λ²μ§Έ λ©€λ² ν¨μλ₯Ό μμ νμ§ μμΌλ©° μ΄κ²μ΄ μ€λ²λ‘λλμ΄μΌνλ€κ³ λ―Ώλ λ¬Έμ μμ λΉλ‘―λ κ²μΌλ‘ μκ°ν©λλ€.
λ΅λ³
SFINAEλ ν νλ¦¬νΈ μΈμμ μΈμ 곡μ λ₯Ό λ체νμ¬ κ΅¬λ¬Έμ΄ μλͺ»λ κ²½μ°μλ§ μλν©λλ€. κ·Έλ¬ν λ체λ μμ΅λλ€.
λλ κ·Έ μκ°νκ³ μ¬μ©νλ €
std::is_same< T, int >::value
νκ³! std::is_same< T, int >::value
μλμ΄ κ°μ κ²°κ³Όλ₯Ό μ 곡ν©λλ€.
ν΄λμ€ ν
νλ¦Ώμ΄ μΈμ€ν΄μ€ν λ λ ( Y<int>
λ€λ₯Έ κ²½μ° μ€ μ νμ κ°μ²΄λ₯Ό λ§λ€ λ λ°μ ) λͺ¨λ λ©€λ² μ μΈμ μΈμ€ν΄μ€νν΄μΌν©λλ€ (μ μ / λ³Έλ¬Έμ μλλλ€!). κ·Έμ€μλ λ©€λ² ν
νλ¦Ώλ μμ΅λλ€. T
κ·Έλ μλ €μ§ μ¬μ€ μ΄λ©° !std::is_same< T, int >::value
κ±°μ§μ΄λ©λλ€. κ·Έλμ κ·Έκ²μ Y<int>
ν¬ν¨ νλ ν΄λμ€ λ₯Ό λ§λ€ κ²μ
λλ€
class Y<int> {
public:
/* instantiated from
template < typename = typename std::enable_if<
std::is_same< T, int >::value >::type >
T foo() {
return 10;
}
*/
template < typename = typename std::enable_if< true >::type >
int foo();
/* instantiated from
template < typename = typename std::enable_if<
! std::is_same< T, int >::value >::type >
T foo() {
return 10;
}
*/
template < typename = typename std::enable_if< false >::type >
int foo();
};
μ std::enable_if<false>::type
κ·Έ μ μΈμ΄ μλͺ» νμ±λλλ‘, μ‘΄μ¬νμ§ μλ μ νμ μ‘μΈμ€ν©λλ€. λ°λΌμ νλ‘κ·Έλ¨μ΄ μ ν¨νμ§ μμ΅λλ€.
enable_if
λ©€λ² ν
νλ¦Ώ μμ²΄κ° λ©€λ² ν
νλ¦Ώμ λ§€κ° λ³μμ μ’
μ λλλ‘ν΄μΌ ν©λλ€. κ·Έλ¬λ©΄ μ 체 μ νμ΄ μ¬μ ν μ’
μμ μ΄λ―λ‘ μ μΈμ΄ μ ν¨ν©λλ€. μ΄ μ€ νλλ₯Ό νΈμΆνλ €κ³ νλ©΄ ν
νλ¦Ώ μΈμμ λν μΈμ 곡μ κ° λ°μνκ³ SFINAEκ° μμλλ‘ λ°μν©λλ€. μ΄ μ§λ¬Έ κ³Ό κ·Έμ λν λ΅λ³μ μ°Έμ‘°νμμμ€ .
λ΅λ³
λλμ΄ μ§§μ μλ₯Ό λ§λ€μμ΅λλ€.
#include <iostream>
#include <type_traits>
class foo;
class bar;
template<class T>
struct is_bar
{
template<class Q = T>
typename std::enable_if<std::is_same<Q, bar>::value, bool>::type check()
{
return true;
}
template<class Q = T>
typename std::enable_if<!std::is_same<Q, bar>::value, bool>::type check()
{
return false;
}
};
int main()
{
is_bar<foo> foo_is_bar;
is_bar<bar> bar_is_bar;
if (!foo_is_bar.check() && bar_is_bar.check())
std::cout << "It works!" << std::endl;
return 0;
}
λ΄κ° μμΈν μ€λͺ νκ³ μΆμ κ²½μ° μ견μ λ§νμμμ€. λλ μ½λκ° λ€μ μλͺ νλ€κ³ μκ°νμ§λ§ λ€μ ν λ² νλ Έλ€. π
μ¬κΈ° μμ μ€μ λ‘ λ³Ό μ μμ΅λλ€ .
λ΅λ³
βμλνλβμ루μ μ μ°Ύκ³ μλ νλ° μλ€μκ² :
#include <utility>
#include <iostream>
template< typename T >
class Y {
template< bool cond, typename U >
using resolvedType = typename std::enable_if< cond, U >::type;
public:
template< typename U = T >
resolvedType< true, U > foo() {
return 11;
}
template< typename U = T >
resolvedType< false, U > foo() {
return 12;
}
};
int main() {
Y< double > y;
std::cout << y.foo() << std::endl;
}
λ€μκ³Ό κ°μ΄ μ»΄νμΌνμμμ€.
g++ -std=gnu++14 test.cpp
λ¬λμ λ€μμ μ 곡ν©λλ€.
./a.out
11
λ΅λ³
μμ μ΄ κ²μλ¬Ό :
κΈ°λ³Έ ν νλ¦Ώ μΈμλ ν νλ¦Ώ μλͺ μ μΌλΆκ° μλλλ€
κ·Έλ¬λ λ€μκ³Ό κ°μ΄ ν μ μμ΅λλ€.
#include <iostream>
struct Foo {
template < class T,
class std::enable_if < !std::is_integral<T>::value, int >::type = 0 >
void f(const T& value)
{
std::cout << "Not int" << std::endl;
}
template<class T,
class std::enable_if<std::is_integral<T>::value, int>::type = 0>
void f(const T& value)
{
std::cout << "Int" << std::endl;
}
};
int main()
{
Foo foo;
foo.f(1);
foo.f(1.1);
// Output:
// Int
// Not int
}
λ΅λ³
μ΄ λ¬Έμ λ₯Ό ν΄κ²°νλ ν κ°μ§ λ°©λ²μ λ©€λ² ν¨μμ νΉμνλ₯Ό λ€λ₯Έ ν΄λμ€μ νΉμν ν λ€μ ν΄λΉ ν΄λμ€μμ μμνλ κ²μ λλ€. λ€λ₯Έ λͺ¨λ κΈ°λ³Έ λ°μ΄ν°μ μ‘μΈμ€νλ €λ©΄ μμ μμλ₯Ό λ³κ²½ν΄μΌ ν μλ μμ§λ§μ΄ κΈ°μ μ μλν©λλ€.
template< class T, bool condition> struct FooImpl;
template<class T> struct FooImpl<T, true> {
T foo() { return 10; }
};
template<class T> struct FoolImpl<T,false> {
T foo() { return 5; }
};
template< class T >
class Y : public FooImpl<T, boost::is_integer<T> > // whatever your test is goes here.
{
public:
typedef FooImpl<T, boost::is_integer<T> > inherited;
// you will need to use "inherited::" if you want to name any of the
// members of those inherited classes.
};
μ΄ κΈ°μ μ λ¨μ μ λ€λ₯Έ λ©€λ² ν¨μμ λν΄ λ§μ λ€λ₯Έ κ²λ€μ ν μ€νΈν΄μΌ ν κ²½μ° κ° ν΄λμ€λ§λ€ ν΄λμ€λ₯Ό λ§λ€κ³ μμ νΈλ¦¬μ μ°κ²°ν΄μΌνλ€λ κ²μ λλ€. κ³΅ν΅ λ°μ΄ν° λ©€λ²μ μ‘μΈμ€νλ κ²½μ°μ ν΄λΉλ©λλ€.
μ μ:
template<class T, bool condition> class Goo;
// repeat pattern above.
template<class T, bool condition>
class Foo<T, true> : public Goo<T, boost::test<T> > {
public:
typedef Goo<T, boost::test<T> > inherited:
// etc. etc.
};
λ΅λ³
λΆμΈμ μΆλ‘ λλ ν νλ¦Ώ λ§€κ° λ³μμ μμ‘΄ν΄μΌν©λλ€. λ°λΌμ μμ νλ μ¬μ΄ λ°©λ²μ κΈ°λ³Έ λΆμΈ λ§€κ° λ³μλ₯Ό μ¬μ©νλ κ²μ λλ€.
template< class T >
class Y {
public:
template < bool EnableBool = true, typename = typename std::enable_if<( std::is_same<T, double>::value && EnableBool )>::type >
T foo() {
return 10;
}
};
κ·Έλ¬λ λ©€λ² ν¨μλ₯Ό μ€λ²λ‘λνλ €λ κ²½μ°μλ μλνμ§ μμ΅λλ€. λμ Tick λΌμ΄λΈλ¬λ¦¬ TICK_MEMBER_REQUIRES
μμ μ¬μ©νλ κ²μ΄ κ°μ₯ μ’μ΅λλ€ .
template< class T >
class Y {
public:
TICK_MEMBER_REQUIRES(std::is_same<T, double>::value)
T foo() {
return 10;
}
TICK_MEMBER_REQUIRES(!std::is_same<T, double>::value)
T foo() {
return 10;
}
};
λν λ€λ₯Έ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ§ μμΌλ €λ κ²½μ°λ₯Ό μν΄ μμ μ λ©€λ²μ λ€μκ³Ό κ°μ 맀ν¬λ‘κ° νμν©λλ€.
template<long N>
struct requires_enum
{
enum class type
{
none,
all
};
};
#define MEMBER_REQUIRES(...) \
typename requires_enum<__LINE__>::type PrivateRequiresEnum ## __LINE__ = requires_enum<__LINE__>::type::none, \
class=typename std::enable_if<((PrivateRequiresEnum ## __LINE__ == requires_enum<__LINE__>::type::none) && (__VA_ARGS__))>::type
λ΅λ³
λ€μμ 맀ν¬λ‘λ₯Ό μ¬μ©ν λ―Έλλ©λ¦¬μ¦ μμ
λλ€. enable_if((...))
λ 볡μ‘ν ννμμ μ¬μ©ν λλ μ΄μ€ κ΄νΈ λ₯Ό μ¬μ© νμμμ€ .
template<bool b, std::enable_if_t<b, int> = 0>
using helper_enable_if = int;
#define enable_if(value) typename = helper_enable_if<value>
struct Test
{
template<enable_if(false)>
void run();
}