0

私は現在、いくつかの柔軟なコンパイル時の数学ライブラリを作成しようとしていますが、なんとか取り除くことができない置換の失敗に遭遇しました。ここに問題があります:

まず、有理数のクラスを作成します。必要な部分だけを記述します。

template<typename T>
class rational
{
    static_assert(std::is_integral<T>::value, "Can only contain integral values.");

    public:

        constexpr rational(T numerator, T denominator);

    private:

        T _numerator;
        T _denominator;
};

また、ライブラリを柔軟にするために、演算子関数の呼び出しを有理数、有理数、積分数に制限するためにSFINAEを多用しようとしていましたが、これは積分と基礎となるものが何であれ機能します。積分のタイプはです。operator+たとえば、関数宣言は次のとおりです。

template<typename T, typename U>
constexpr
rational<typename std::common_type<T, U>::type>
operator+(const rational<T>& lhs, const rational<U>& rhs);

template<typename T, typename U>
constexpr
typename std::enable_if<std::is_integral<U>::value, rational<typename std::common_type<T, U>::type>>::type
operator+(const rational<T>& lhs, const U& rhs);

template<typename T, typename U>
constexpr
typename std::enable_if<std::is_integral<T>::value, rational<typename std::common_type<T, U>::type>>::type
operator+(const T& lhs, const rational<U> rhs);

そして、ここにコードの欠陥のあるセグメントがあります。クラッシュは発生しませんstatic_assertが、おそらく置換の失敗が原因です。

constexpr auto r1 = rational<int>(1, 2);
constexpr auto r2 = rational<int>(2, 4);
static_assert(r1 + r2 == rational<int>(1, 1), "");

エラーは次のとおりです(周囲のblablaなしでエラーを保持しただけです):

... required by substitution of 'template<class T, class U> constexpr typename std::enable_if<std::is_integral<T>::value, smath::rational<typename std::common_type<_Tp, _Up>::type> >::type smath::operator+(const T&, smath::rational<U>) [with T = smath::rational<int>; U = int]'
... required from here
... error: operands to ?: have different types 'smath::rational<int>' and 'int'
... required by substitution of 'template<class T, class U> constexpr typename std::enable_if<std::is_integral<U>::value, smath::rational<typename std::common_type<_Tp, _Up>::type> >::type smath::operator+(const smath::rational<T>&, const U&) [with T = int; U = smath::rational<int>]'
... required from here
... error: operands to ?: have different types 'int' and 'smath::rational<int>'

私の推測では、g ++は、2つの有理数で機能する最初のテンプレート関数を選択し、それで問題ないだろうと思いました。ただし、それでも最後の2つの関数を適用しようとし、実行しようとして失敗したようです。理解できないこと。いくつかの助けを歓迎します:)

編集:rationalコンストラクターexplicitを使用すると問題が解決するようです。これはすばらしいことです。しかし、なぜ置換がそれほど難しく失敗したのかを知りたいと思っています。

4

1 に答える 1

1

問題は、に渡されるタイプstd::enable_if<whatever, T>です。置換が失敗したとしても、議論は合理的である必要がありますが、そうではありません。したがって、typename std::common_type<T, U>::type評価される可能性のあるタイプにそのようなタイプがない場合、の使用は機能しません。あなたは何か他のものが必要になるでしょう。動作するのは、テンプレート引数リストの整数/有理数の混合オーバーロードを無効にする置換失敗を作成することです。

template<typename T, typename U, typename = typename std::enable_if<std::is_integral<U>::value, void>::type>
constexpr
rational<typename std::common_type<T, U>::type>
operator+(const rational<T>& lhs, const U& rhs);

template<typename T, typename U, typename = typename std::enable_if<std::is_integral<T>::value, void>::type>
constexpr
rational<typename std::common_type<T, U>::type>
operator+(const T& lhs, const rational<U> rhs);

今のところ、これがgccの問題の回避策なのか、それともそのようにする必要があるのか​​、完全にはわかりません。

于 2012-09-05T22:50:45.773 に答える