エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

自作の中置演算子で広がる世界

おとといのエントリで書いた演算子を、汎用的に使えるようにしてみました。

// Operators.h

#ifndef OPERATORS_H
#define OPERATORS_H

template<typename T, typename U>
struct Operator
{
    explicit Operator(const T& lhs) : lhs(lhs) {}
    const T& lhs;
};

template<typename T, typename U>
inline Operator<T, U> operator % (const T& lhs, U)
{
    return Operator<T, U>(lhs);
}

#endif//OPERATORS_H

これを使っていろいろやってみたいと思います。

power

C++では冪乗のための演算子がありません。

x ** y

こんなふうに書けるとうれしいんですが、百歩ほどゆずって

x %power% y

というのをやってみます。

#include <iostream>
#include <cmath>

#include "Operators.h"

enum POWER { power };

inline double operator % (const Operator<double, POWER>& op, int rhs)
{
    return pow(op.lhs, rhs);
}

int main(int, char* [])
{
    for(int i = -3; i <= 3; ++i)
    {
        std::cout << "5 power " << i << " = " << (5.0 %power% i) << "\n";
    }

    return 0;
}


実行してみるとこんな感じ。

5 power -3 = 0.008
5 power -2 = 0.04
5 power -1 = 0.2
5 power 0 = 1
5 power 1 = 5
5 power 2 = 25
5 power 3 = 125

5 %power% iと書けるといいんですが、型が合わなくなるのでコンパイルできません。詰めが甘いです。

times

Rubyでいうところの

sum = 0
10.times do |n|
  sum += n
end
puts "0+1+...+9 = #{sum}"

これをやってみます。

#include "Operators.h"

enum TIMES { times };

template<typename Func_T>
inline void operator % (const Operator<int, TIMES>& op, Func_T rhs)
{
    for(int i = 0; i < op.lhs; ++i)
    {
        rhs(i);
    }
}

// つづく...

ここまでがtimesを実現するためのコード。
以下が利用例。

// ...つづき

#include <functional>
#include <iostream>

struct Summater : public std::unary_function<int, void>
{
    int& sum;

    explicit Summater(int& sum) : sum(sum) {}

    void operator () (int n)
    {
        sum += n;
    }
};

int main(int, char* [])
{
    int sum = 0;

    10 %times% Summater(sum);

    std::cout << "0+1+...+9 = " << sum << std::endl;

    return 0;
}


不格好だけど、できた。できた…と言っていいんじゃないかな?

each

timesができたんならeachもできるだろう、ということで迷わず前進。

#include <iostream>
#include <vector>
#include <set>
#include <functional>

#include "Operators.h"

enum EACH { each };

template<typename T, typename Func_T>
inline void operator % (const Operator<T, EACH>& op, Func_T rhs)
{
    for(typename T::const_iterator i = op.lhs.begin(); i != op.lhs.end(); ++i)
    {
        rhs(*i);
    }
}

struct Writer : public std::unary_function<int, void>
{
    void operator () (int n)
    {
        std::cout << n << std::endl;
    }
};

int main(int, char* [])
{
    Writer writer;

    std::vector<int> v;

    v.push_back(1);
    v.push_back(2);
    v.push_back(3);

    // std::vector を each
    v %each% writer;

    std::set<int> s;

    s.insert(1);
    s.insert(2);
    s.insert(3);

    // std::set だって each
    s %each% writer;

    return 0;
}

総括

書いていて楽しいけれど、効果的かどうかは疑問。効果の割にコストが高過ぎるかも。