νƒœκ·Έ 보관물: g++

g++

멀버 ν•¨μˆ˜λ₯Ό μ‘°κ±΄λΆ€λ‘œ μ»΄νŒŒμΌν•˜κΈ°μœ„ν•œ std :: enable_if λ…Έλ ₯ν•œ 후에 λ„ˆν¬λ“€μ—κ²Œ λ‚΄

μ‚¬μš©λ²•μ„ μ΄ν•΄ν•˜κΈ° μœ„ν•΄ κ°„λ‹¨ν•œ 예제λ₯Ό μ–»μœΌλ €κ³ ν•©λ‹ˆλ‹€ 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();
}