本の虫

著者:江添亮
ブログ: http://cpplover.blogspot.jp/
メール: boostcpp@gmail.com
Twitter: https://twitter.com/EzoeRyou
GitHub: https://github.com/EzoeRyou

アマゾンの江添のほしい物リストを著者に送るとブログ記事のネタになる

筆者にブログのネタになる品物を直接送りたい場合、住所をメールで質問してください。

コンパイル時分岐

独自実装の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 > ;