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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Boost

Boost (ブースト)は、C++の先駆的な開発者のコミュニティ、 またそのコミュニティによって公開されているオープンソースライブラリのことを指します。

Q&A

解決済

3回答

3810閲覧

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

katahiromz

総合スコア186

C++11

C++11は2011年に容認されたC++のISO標準です。以前のC++03に代わるもので、中枢の言語の変更・修正、標準ライブラリの拡張・改善を加えたものです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Boost

Boost (ブースト)は、C++の先駆的な開発者のコミュニティ、 またそのコミュニティによって公開されているオープンソースライブラリのことを指します。

1グッド

0クリップ

投稿2016/10/25 01:47

編集2016/10/25 08:24

こんにちは、コンピュータ研究家の片山博文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は、実質的に次のコードと同じです。

C++

1#define UNBOOST_USE_CHRONO 2#include <unboost.hpp> 3int main(void) { 4 using namespace unboost::chrono; 5 std::cout << "chrono" << std::endl; 6 { 7 std::cout << "MMMM" << std::endl; 8 seconds s = hours(1) + minutes(1); 9 } 10 std::cout << "success" << std::endl; 11 12 return 0; 13}

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

C++

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

の一行になります。

hoursは、

C++

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

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

C++

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

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

また、minutesは、

C++

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

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

C++

1 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行目の

C++

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

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

C++

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

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

C++

1 unboost::chrono::common_duration_type< 2 unboost::chrono::duration<...>, 3 unboost::chrono::duration<...>>

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

C++

1std::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>>になっていて、これがコンストラクタの

C++

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

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

C++

1 typedef ratio_divide<Period, to_period> cf;

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

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

Bakudankun👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Bakudankun

2016/10/25 04:52

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

2016/10/25 05:20

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

2016/10/25 07:32

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

2016/10/25 09:14

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

回答3

0

自己解決

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

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

投稿2016/10/29 01:19

katahiromz

総合スコア186

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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 08:14

PineMatsu

総合スコア3579

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

katahiromz

2016/10/25 08:27

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

2016/10/25 08:51

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

2016/10/25 09:45

これ、VC++14だとstd::chronoが呼ばれるようになってるんですね。 で、UNBOOSTの部分を通そうと、ちょっとだけソースをいじらせてもらって、UNBOOST_USE_WIN32_CHRONOとUNBOOST_USE_INBOOST_RATIOを定義してコンパイルしたら、やはりエラーなく通ります。 なので、Builder 5.5.1のテンプレート処理に問題があるようにしか思えないですね。 回避策は思いつきません。 「C++テンプレートテクニック」の著者の高橋晶さんあたりに直接投げかけてみるかですね。あの人ブログを持たれているので、そこで質問してみてはどうでしょう? (http://faithandbrave.hateblo.jp/)
guest

0

こんにちは。

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

C++

1#define UNBOOST_STATIC_ASSERT_MSG(x,y) \ 2 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()を使えば、行けそうな感じがします。

C++

1namespace boost{ 2 3// HP aCC cannot deal with missing names for template value parameters 4template <bool x> struct STATIC_ASSERTION_FAILURE; 5 6template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; }; 7 8// HP aCC cannot deal with missing names for template value parameters 9template<int x> struct static_assert_test{}; 10 11} 12 13 14# define BOOST_STATIC_ASSERT(B) \ 15 enum { BOOST_JOIN(boost_static_assert_enum_, __LINE__) \ 16 = sizeof(::boost::STATIC_ASSERTION_FAILURE< (bool)( B ) >) }
suffix.hpp抜粋

C++

1#define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y ) 2#define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y) 3#define BOOST_DO_JOIN2( X, Y ) X##Y

投稿2016/10/25 05:50

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

katahiromz

2016/10/25 06:12

>static_assert.hppで定義されている下記がBorland C++ 5.5.1と互換性がないということですね。 違います。サンプルのchronoがコンパイルできない問題です。 UNBOOST_STATIC_ASSERT_MSGは正しく失敗しています。UNBOOST_STATIC_ASSERT_MSGには何の問題はありません。 Borlandのコンパイル時定数の解釈がおかしく、なぜかゼロのratioになってしまうという問題です。
Chironian

2016/10/25 07:06

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問