2016-08-01 10 views
2

私は小さなライブラリに取り組んでいます。私がする必要があることの1つは、訪問者をデータに適用して結果を返すことです。なぜ `std :: common_type_t <std :: ostream&、std :: ostream&>`は `std :: ostream`ではなく` std :: ostream`と同じですか?

古いC++コードでは、訪問者はtypedef return_typeと宣言される予定でした。たとえば、boost::static_visitorとなります。

新しいコードでは、これらの訪問者はすべて非推奨です。 C++ 14では通常decltype(auto)を使うことができますが、私はstd::common_typeのようなものを使ってそれをやろうとしていますので、C++ 11で行うことができます。

例実装std::common_typeをC++ 11にバックポートし、それを使用して戻り値の型を特定しました。 std::common_type_t<std::ostream&, std::ostream&>の結果は

cppreference.com

#include <ostream> 
#include <type_traits> 

// decay_t backport 

template <typename T> 
using decay_t = typename std::decay<T>::type; 

// common_type backport 

template <typename T, typename... Ts> 
struct common_type; 

template <typename T> 
struct common_type<T> { 
    using type = decay_t<T>; 
}; 

template <typename T1, typename T2> 
struct common_type<T1, T2> { 
    using type = decay_t<decltype(true ? std::declval<T1>() : std::declval<T2>())>; 
}; 

// TODO: Is this needed? 
/* 
template <typename T> 
struct common_type<T, T> { 
    using type = T; 
}; 
*/ 

template <typename T1, typename T2, typename T3, typename... Ts> 
struct common_type<T1, T2, T3, Ts...> { 
    using type = typename common_type<typename common_type<T1, T2>::type, T3, Ts...>::type; 
}; 

template <typename T, typename... Ts> 
using common_type_t = typename common_type<T, Ts...>::type; 

// static_assert(std::is_same<common_type_t<std::ostream &, std::ostream &>, std::ostream &>::value, "This is what I expected!"); 
static_assert(std::is_same<common_type_t<std::ostream &, std::ostream &>, std::ostream>::value, "Hmm..."); 

int main() {} 

の「可能な実装」を使用しているとき、私はいくつかの予期しない結果を得るしかし、何をしても、「すべきですか」? std::ostream &でなければなりませんか?そうでない場合、なぜgcc 5.4.0clang 3.8.0の両方がstd::ostreamだと思いますか?

注:実際のstd::common_type_tをC++ 14で使用すると、まだstd::ostreamで、std::ostream &ではなくなります。

が常に有効な方法であるようにstd::common_typeを特化していますか?私のプログラムでうまくいくようですが、ハックのように感じます。

+2

関連:http://stackoverflow.com/q/21975812/2069064、しかし 'common_type'はあなたに悲しい顔があるので参考にしません。 – Barry

+0

ありがとうございます。だから私は 'std :: declval'をそこに使ってはいけないと思いますか? 'decltype(true?std :: forward (std :: declval ()):std :: forward (std :: decl())')を使うべきですか?私はこれが実際にはかなりトリッキーだと思う...'テンプレート をmini_decay_t = conditional_t < のstd :: is_lvalue_reference ::値を使用して: –

答えて

2

common_typeの歴史に関する関連の議論については、this questionを参照してください。なぜ実際には参照を生成しないのですか。

は常に有効なアプローチであるようにstd::common_typeを特化していますか?

私はあなたが(あなたが他のものを特化することはできませんので)common_typeのご実装を専門と意味を前提としています。そして、それは十分ではありません。 common_type<Base&, Derived&>Base&になりますが、そのインスタンス化は特殊化されません。

にはを使用しません。decayを使用してください。 decayがそこにある理由は、declvalが提供するいくつかの驚きの基準値を削除することです。

template <class T> 
using common_decay_t = std::conditional_t< 
    std::is_lvalue_reference<T>::value, 
    T, 
    std::remove_reference_t<T>>; 

、通常のdecayするのではなく、それを使用しますので、ちょうどあなた自身のタイプの形質を追加 - しかし、あなたは左辺値参照を維持したいです。

+0

[OK]を、私はこれを試しますが、私は私も正しいようにあなたの答えをマーク、今のこのバージョンで働いていると思い –

+0

ありがとうございました、 T、 decay_t >; ' –

関連する問題