2014-11-08

コンパイル時分岐

独自実装のintervalクラスでメンバ関数sin()を実装した。しかし、ジェネリックなコードが書きたい。 sin(x)とかいたとき、intervalならx.sin()を、でなければstd::sin(x)を呼び出したい。 こんなときどうすれば良い?

プライマリテンプレートと明示的特殊化を使って、コンパイル時に条件分岐を行えばよい。


#include <cmath>
#include <type_traits>

struct interval
{
    double sin( ) const
    {
        // unimplemented
        return 0.0 ;
    }
} ;

// プライマリーテンプレート
// デフォルトの実装
template < typename T >
struct dispatch
{
    static double invoke( T const & value )
    {
        return std::sin( value ) ;
    }
} ;

// interval型に対して明示的特殊化
template < >
struct dispatch<interval>
{
    static double invoke( interval const & value )
    {
        return value.sin() ;
    }
} ;

template < typename T >
void f( T const & x )
{
    double s = dispatch<T>::invoke(x) ;
}

int main()
{
    double d = 1.0 ;
    f( d ) ;
    
    interval i ;
    f( i ) ;
}

以下のように書くこともできる。

struct generic_sin
{
    template < typename T >
    static double invoke( T const & value )
    {
        return std::sin( value ) ;
    }
} ;

struct interval_sin
{
    static double invoke( interval const & value )
    {
        return value.sin() ;
    }
} ;

template < typename T >
using dispatch = std::conditional_t< std::is_same<T, interval>::value, 
    interval_sin, generic_sin > ;

1 comment:

Anonymous said...

よくわからない
sin(interval)のオーバーロードでは何がいけないんです?