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

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

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

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

Q&A

解決済

1回答

651閲覧

構造体とtemplateの関係

Y.R.T

総合スコア42

C++

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

0グッド

0クリップ

投稿2020/08/31 06:18

編集2020/08/31 06:19

さまざまな温度単位のリテラルという題の構文なのですが、
template <scale R, scale S>
constexpr quantity<R> temperature_cast(quantity<S> const q)
{
return quantity<R>(conversion_traits<S, R>::convert(static_cast<double>(q)));
}

conversion_traitsは構造体の型かともいますが、
この構造体のRとSは構造体の中の計算で使用されていないのですが、
どう考えたらいいですか?

また、conversion_traitsの構造体は、
main関数ではどのように選択されますか?

#include <cmath> #include <assert.h> bool are_equal(double const d1, double const d2, double const epsilon = 0.001) { return std::fabs(d1 - d2) < epsilon; } namespace temperature { enum class scale { celsius, fahrenheit, kelvin }; template <scale S> class quantity { const double amount; public: constexpr explicit quantity(double const a) : amount(a) {} explicit operator double() const { return amount; } }; template <scale S> inline bool operator==(quantity<S> const& lhs, quantity<S> const& rhs) { return are_equal(static_cast<double>(lhs), static_cast<double>(rhs)); } template <scale S> inline bool operator!=(quantity<S> const& lhs, quantity<S> const& rhs) { return !(lhs == rhs); } template <scale S> inline bool operator< (quantity<S> const& lhs, quantity<S> const& rhs) { return static_cast<double>(lhs) < static_cast<double>(rhs); } template <scale S> inline bool operator> (quantity<S> const& lhs, quantity<S> const& rhs) { return rhs < lhs; } template <scale S> inline bool operator<=(quantity<S> const& lhs, quantity<S> const& rhs) { return !(lhs > rhs); } template <scale S> inline bool operator>=(quantity<S> const& lhs, quantity<S> const& rhs) { return !(lhs < rhs); } template <scale S> constexpr quantity<S> operator+(quantity<S> const& q1, quantity<S> const& q2) { return quantity<S>(static_cast<double>(q1) + static_cast<double>(q2)); } template <scale S> constexpr quantity<S> operator-(quantity<S> const& q1, quantity<S> const& q2) { return quantity<S>(static_cast<double>(q1) - static_cast<double>(q2)); } template <scale S, scale R> struct conversion_traits { static double convert(double const value) = delete; }; template <> struct conversion_traits<scale::celsius, scale::kelvin> { static double convert(double const value) { return value + 273.15; } }; template <> struct conversion_traits<scale::kelvin, scale::celsius> { static double convert(double const value) { return value - 273.15; } }; template <> struct conversion_traits<scale::celsius, scale::fahrenheit> { static double convert(double const value) { return (value * 9) / 5 + 32;; } }; template <> struct conversion_traits<scale::fahrenheit, scale::celsius> { static double convert(double const value) { return (value - 32) * 5 / 9; } }; template <> struct conversion_traits<scale::fahrenheit, scale::kelvin> { static double convert(double const value) { return (value + 459.67) * 5 / 9; } }; template <> struct conversion_traits<scale::kelvin, scale::fahrenheit> { static double convert(double const value) { return (value * 9) / 5 - 459.67; } }; template <scale R, scale S> constexpr quantity<R> temperature_cast(quantity<S> const q) { return quantity<R>(conversion_traits<S, R>::convert(static_cast<double>(q))); } namespace temperature_scale_literals { constexpr quantity<scale::celsius> operator "" _deg(long double const amount) { return quantity<scale::celsius> {static_cast<double>(amount)}; } constexpr quantity<scale::fahrenheit> operator "" _f(long double const amount) { return quantity<scale::fahrenheit> {static_cast<double>(amount)}; } constexpr quantity<scale::kelvin> operator "" _k(long double const amount) { return quantity<scale::kelvin> {static_cast<double>(amount)}; } } } int main() { using namespace temperature; using namespace temperature_scale_literals; auto t1{ 36.5_deg }; auto t2{ 79.0_f }; auto t3{ 100.0_k }; { auto tf = temperature_cast<scale::fahrenheit>(t1); auto tc = temperature_cast<scale::celsius>(tf); assert(t1 == tc); } { auto tk = temperature_cast<scale::kelvin>(t1); auto tc = temperature_cast<scale::celsius>(tk); assert(t1 == tc); } { auto tc = temperature_cast<scale::celsius>(t2); auto tf = temperature_cast<scale::fahrenheit>(tc); assert(t2 == tf); } { auto tk = temperature_cast<scale::kelvin>(t2); auto tf = temperature_cast<scale::fahrenheit>(tk); assert(t2 == tf); } { auto tc = temperature_cast<scale::celsius>(t3); auto tk = temperature_cast<scale::kelvin>(tc); assert(t3 == tk); } { auto tf = temperature_cast<scale::fahrenheit>(t3); auto tk = temperature_cast<scale::kelvin>(tf); assert(t3 == tk); } }

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

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

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

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

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

guest

回答1

0

ベストアンサー

RとSは構造体の中の計算で使用されていないのですが

  • conversion_traits<scale::celsius, scale::kelvin>::convert(double const value)
  • conversion_traits<scale::kelvin, scale::celsius>::convert(double const value)
  • conversion_traits<scale::celsius, scale::fahrenheit>::convert(double const value)
  • conversion_traits<scale::fahrenheit, scale::celsius>::convert(double const value)
  • conversion_traits<scale::fahrenheit, scale::kelvin>::convert(double const value)
  • conversion_traits<scale::kelvin, scale::fahrenheit>::convert(double const value)

を呼び分けるのに使っています。

main関数ではどのように選択されますか?

temperature_cast<scale::fahrenheit>(t1);なら、<>内がR、引数t1の型(quantity<scale::celsius>)の<>内がSとなり、

C++

1 template <scale R, scale S> 2 constexpr quantity<R> temperature_cast(quantity<S> const q) 3 { 4 return quantity<R>(conversion_traits<S, R>::convert(static_cast<double>(q))); 5 }

conversion_traits<scale::celsius, scale::fahrenheit>::convert(static_cast<double>(t1))が呼ばれます。

投稿2020/08/31 08:07

編集2020/08/31 08:32
SHOMI

総合スコア4079

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

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

Y.R.T

2020/09/01 01:01

conversion_traits<scale::celsius, scale::kelvin>::convert(double const value) conversion_traits<scale::kelvin, scale::celsius>::convert(double const value) conversion_traits<scale::celsius, scale::fahrenheit>::convert(double const value) conversion_traits<scale::fahrenheit, scale::celsius>::convert(double const value) conversion_traits<scale::fahrenheit, scale::kelvin>::convert(double const value) conversion_traits<scale::kelvin, scale::fahrenheit>::convert(double const value) を呼び分けるのに使っています。 というのは、例えば template <> struct conversion_traits<scale::kelvin, scale::fahrenheit> { static double convert(double const value) { return (value * 9) / 5 - 459.67; } }; 等を呼び出すで間違いないでしょうか? また、最後の conversion_traits<scale::celsius, scale::fahrenheit>::convert(static_cast<double>(t1)) が呼び出されます。 の(t1)は、(long double const amount)に相当しますか?
SHOMI

2020/09/01 01:19 編集

>等を呼び出すで間違いないでしょうか? そうです。それを呼んでいるのが template <scale R, scale S> constexpr quantity<R> temperature_cast(quantity<S> const q) です。 >conversion_traits<scale::celsius, scale::fahrenheit>::convert(static_cast<double>(t1)) が呼び出されます。 >の(t1)は、(long double const amount)に相当しますか? 回答にはstatic_cast<double>(t1)と書きましたが、正確にはtemperature_castの引数qに渡しているのがt1で、static_cast<double>(q)がconvertの引数valueに渡されます。 static_cast<double>(q)によりquantityクラスのexplicit operator double() constが呼ばれ、メンバに保持しているdouble値が取り出されます。
Y.R.T

2020/09/01 02:48

ありがとうございます。 struct conversion_traits の種類の選択は どこで決まりますか?
SHOMI

2020/09/01 02:50

回答の「main関数ではどのように選択されますか?」に書いています。
Y.R.T

2020/09/01 03:33

何度も同じことを質問してすみません。 まだ、曖昧なのですが、 まずmain関数の auto tf = temperature_cast<scale::fahrenheit>(t1); で<scale::fahrenheit> が<R>に相当する。 (t1)が template <scale R, scale S> constexpr quantity<R> temperature_cast(quantity<S> const q) { return quantity<R>(conversion_traits<S, R>::convert(static_cast<double>(q))); } の(static_cast<double>(q))に相当する。 ここからどのように<S>が決まりますか?
SHOMI

2020/09/01 03:41 編集

>(t1)が(static_cast<double>(q))に相当する。 違います。 t1はauto t1{ 36.5_deg };でquantity<scale::celsius>型です。 temperature_castに渡しているt1がquantity<scale::celsius>型なので、 temperature_cast(quantity<S> const q)のSはscale::celsiusになります。
Y.R.T

2020/09/01 04:11

enum class scale { celsius, fahrenheit, kelvin }; で型が決まっているので合っていますか?
SHOMI

2020/09/01 04:31 編集

t1はauto t1{ 36.5_deg };で36.5に_degがついているので、 constexpr quantity<scale::celsius> operator "" _deg(long double const amount) { return quantity<scale::celsius> {static_cast<double>(amount)}; } でquantity<scale::celsius>型として構築されます。
Y.R.T

2020/09/01 04:45

そういうことなんですね。 最後まで、丁寧に教えていただきありがとうござます。 理解できました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問