質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.92%

C++のテンプレートがうまく動かない

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,964

katahiromz

score 131

こんにちは、コンピュータ研究家の片山博文MZです。現在、Unboostというライブラリを作っています。Unboostは、C++11やBoostをまねたもので、C++03でC++11相当の機能を実現するために作っています。

https://github.com/katahiromz/unboost
https://github.com/katahiromz/unboost/blob/master/unboost/chrono.hpp
https://github.com/katahiromz/unboost/blob/master/samples/chrono.cpp

Unboostのchronoという、時間に関するモジュールですが、これがBorland C++ 5.5.1でうまく動かなくて困っています。

イメージ説明

画像は、chronoのサンプルをコンパイルしたところです。修正方法を教えて下さい。よろしくお願い致します。

(追記)
現在のサンプルのchrono.cppは、実質的に次のコードと同じです。

#define UNBOOST_USE_CHRONO
#include <unboost.hpp>
int main(void) {
    using namespace unboost::chrono;
    std::cout << "chrono" << std::endl;
    {
        std::cout << "MMMM" << std::endl;
        seconds s = hours(1) + minutes(1);
    }
    std::cout << "success" << std::endl;

    return 0;
}

出力を除けば、主な処理は、

seconds s = hours(1) + minutes(1);


の一行になります。

hoursは、

unboost::chrono::duration<_int64_t, unboost::ratio<3600, 1> >


と同じであり、これは1時間という時間の量を表し、

std::chrono::duration<long long, std::ratio<3600, 1>>


と同じように動作することを期待しています。
unboost::ratioは、コンパイル時の有理数を定義し、std::ratioと同じように動作することを期待しています。

また、minutesは、

unboost::chrono::duration<_int64_t, unboost::ratio<60, 1> >


と同じであり、これは60秒という時間の量を表し、

std::chrono::duration<long long, std::ratio<60, 1>>


と同じように動作することを期待しています。

hours(1)は、1時間を表し、unboost/chrono.hppの394行目で初期化されます。
minutes(1)は、1分間を表し、unboost/chrono.hppの394行目で初期化されます。
これで初期化が終わります。ここまでは問題ありません。

次に、hours(1) + minutes(1)という足し算になる訳ですが、unboost/chrono.hppの471行目の

operator+(const unboost::chrono::duration<Rep1, Period1>&, 
          const unboost::chrono::duration<Rep2, Period2>&)


で処理されます。これは、

operator+(const std::chrono::duration<Rep1, Period1>&, 
          const std::chrono::duration<Rep2, Period2>&)


と同じような動作を行うことを期待しています。
operator+(const duration&, const duration&)の中身と戻り値で、

unboost::chrono::common_duration_type<
        unboost::chrono::duration<...>, 
        unboost::chrono::duration<...>>


という型が使われます。このunboost::chrono::common_duration_typeというのは、unboost/chrono.hppの180行目前後で定義されており、C++11の

std::common_type<std::chrono::duration<...>, std::chrono::duration<...>>


と同じ動作になることを期待しています。

しかし、エラーメッセージを見る限りでは、operator+の戻り値の型は、duration<int64, ratio<0, 6>>になっております。unboost/chrono.hppの480行目で、CD(lhs).count()などと書かれておりますが、このCDがduration<int64, ratio<0, 6>>になっていて、これがコンストラクタの

template <class Rep2, class Period2>
    duration(const duration<Rep2, Period2>& d) {
        rep_ = duration_cast<type>(d).count();
    }


を引き起こし、さらにduration_castを引き起こします。duration_castは、unboost/chrono.hppの677行目前後で定義されています。そこで

typedef ratio_divide<Period, to_period> cf;


のように、ピリオドの割り算を行っておりますが、割り算の除数は非ゼロでなければなりません。
しかし、Borland 5.5.1ではto_periodがゼロになっており、そのため、論理エラーが発生し、
UNBOOST_STATIC_ASSERT_MSGの失敗を引き起こします。

これが問題な訳です。回避方法などがございませんか?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Bakudankun

    2016/10/25 13:52

    ざっと見た感じ`unboost/static_assert.hpp`の33行目で使われている`UNBOOST_STATIC_ASSERTION`マクロがどこにも定義されていないように見えるのですが、どこかで定義されていますか?

    キャンセル

  • katahiromz

    2016/10/25 14:20

    「UNBOOST_STATIC_ASSERTION##__LINE__」は、「UNBOOST_STATIC_ASSERTION」と現在の行番号を結合した新しい識別子で、配列型を定義します。配列の要素数が負の値の場合にエラーになるという性質を利用してstatic_assertと同じようなふるまいを実現しています。

    キャンセル

  • Bakudankun

    2016/10/25 16:32

    そういうことでしたか、勉強になります。とりあえず、コードを全部丸投げするのではなく、「うまく動かない」とはどういうことか、何をもって「うまく動く」と判断するのか、どこが原因で「うまく動かない」と思われるのか、できるなら問題を再現する最小限のコードを用意して、質問のスコープを絞るべきだと思います。

    キャンセル

  • yohhoy

    2016/10/25 18:14

    興味本位の質問で大変申し訳ないのですが、2016年にもなった今、なぜBCC 5.5.1を利用/サポートしようとしているのでしょうか?Copyrightにもあるように今から16年も昔のC++コンパイラですし、(タグにある)C++11仕様どころかC++98/03への準拠度も相当怪しいレベルの骨董品と思います。絶対にサポートしたいのだという思いを否定するつもりはないのですが、個人的には少々気になりました。

    キャンセル

回答 3

check解決した方法

0

コンパイル時定数を使わずにauto_durationという中間型を使うことで解決しました。

皆様、ありがとうございました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

こんにちは。

static_assert.hppで定義されている下記がBorland C++ 5.5.1と互換性がないということですね。

#define UNBOOST_STATIC_ASSERT_MSG(x,y) \
    typedef char UNBOOST_STATIC_ASSERTION##__LINE__[(x) ? 1 : -1]

xがfalseになる時、typedef char UNBOOST_STATIC_ASSERTION680[-1]と展開され、要素数-1の配列を定義しようとしてそのようなエラーメッセージになるのだと思います。

boostの同様な定義をみるとびっくり大規模ですが、__BORLANDC__部分は少ないです。
boostのstatic_assert.hppの下記BOOST_STATIC_ASSERT()を使えば、行けそうな感じがします。

namespace boost{

// HP aCC cannot deal with missing names for template value parameters
template <bool x> struct STATIC_ASSERTION_FAILURE;

template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };

// HP aCC cannot deal with missing names for template value parameters
template<int x> struct static_assert_test{};

}


#    define BOOST_STATIC_ASSERT(B) \
         enum { BOOST_JOIN(boost_static_assert_enum_, __LINE__) \
            = sizeof(::boost::STATIC_ASSERTION_FAILURE< (bool)( B ) >) }
 suffix.hpp抜粋
#define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y )
#define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y)
#define BOOST_DO_JOIN2( X, Y ) X##Y

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/10/25 15:12

    >static_assert.hppで定義されている下記がBorland C++ 5.5.1と互換性がないということですね。

    違います。サンプルのchronoがコンパイルできない問題です。

    UNBOOST_STATIC_ASSERT_MSGは正しく失敗しています。UNBOOST_STATIC_ASSERT_MSGには何の問題はありません。

    Borlandのコンパイル時定数の解釈がおかしく、なぜかゼロのratioになってしまうという問題です。

    キャンセル

  • 2016/10/25 16:06

    追いかけてみましたが、かなりややこしいので断念しました。
    型推論規則の相違だろうとは思いますが、どのようにすれば解決するのか見当つきません。
    BC++をダウンロードする気力まではないのでこの辺で。すいません。

    キャンセル

0

最新のBuilderにはboostが付属していたはずですが、確かboostの1.34くらいの古いバージョンだった様な覚えがあります。boost 1.60あたりで動かそうとしたら全くコンパイルできなくて断念した覚えがあります。(それ以来BDSはアンインストールしてしまいました。boostがまともに使えないコンパイラは使う気がしないので)

boost::chronoがもし1.34あたりで付属していたらそのソースを参照してみたらどうでしょうか?

もしくは、chronoはC++11に標準としてサポートされているので、そちらを参照してみてはどうでしょうか?
std::chronoとboost::chronoはほとんど同じ仕様になっていたと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/10/25 17:27

    C++11とBoostを使わない実装の話をしています。C++11とBoostでchronoが使えるのはわかっています。

    キャンセル

  • 2016/10/25 17:51

    すいません。それは判ってるのですが、どれくらい本家?のchronoを参考にされたのかと思いまして。
    で、ちょっと興味が湧いたので、このunboost::chronoとサンプルをVC++14(VS2015)でコンパイルしたら、難なくコンパイルできてしまいました。
    Builder 5.5.1を使える環境がないので何とも言えませんが、コンパイラがこのコードを正常に通さないということしか言えないですね。
    最新のBuilderではどうなのかな?という興味はありますが、Builder 5.5.1でどうしてもというのなら私にはお手上げです。Borland(今はエンバカデロか)に直接問い合わせるか、Builderのユーザーズグループあたりで相談されたほうが早いかもしれません。teratailにBuilderのエキスパートがいるとは限らないので。

    キャンセル

  • 2016/10/25 18:45

    これ、VC++14だとstd::chronoが呼ばれるようになってるんですね。
    で、UNBOOSTの部分を通そうと、ちょっとだけソースをいじらせてもらって、UNBOOST_USE_WIN32_CHRONOとUNBOOST_USE_INBOOST_RATIOを定義してコンパイルしたら、やはりエラーなく通ります。
    なので、Builder 5.5.1のテンプレート処理に問題があるようにしか思えないですね。
    回避策は思いつきません。

    「C++テンプレートテクニック」の著者の高橋晶さんあたりに直接投げかけてみるかですね。あの人ブログを持たれているので、そこで質問してみてはどうでしょう?
    http://faithandbrave.hateblo.jp/

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る