2016-09-13 1 views
9

私は、特定のテンプレートタイプの引数を取る関数を持っています。簡易版は、次のようになります。非constテンプレートの引数型をconstに暗黙的に変換するための標準的な方法はありますか?

機能的
#include <type_traits> 

template <typename T> 
struct foo 
{ 
    // default constructor 
    foo() { } 

    // simple copy constructor that can construct a foo<T> from a foo<T> 
    // or foo<const T> 
    foo(const foo<typename std::remove_const<T>::type> &) { } 
}; 

fooはこの質問に関連していない他のいくつかのアドオン機能で、shared_ptr<T>に似て動作します。関数のセマンティクスは、foo<const T>を取り込むことを好むことを指示する。 foo<const T>foo<T>から暗黙的に構築可能であるので、私は、次のような何かをできるようにしたいと思います:

template <typename T> 
void bar(foo<const T> f) { } 

int main() 
{ 
    bar(foo<const int>()); // fine 
    bar(foo<int>());  // compile error 
} 

取るbarに該当するオーバーロードが存在しないため、これが失敗したfoo<int>foo<const int>は、暗黙のうちに可能性にもかかわらず、 foo<int>から構築、テンプレートのインスタンスと協力してオーバーロードの解決はより厳しいように思われる。

これを達成するための標準的な方法はありますか?私はを取るbar()ための2番目のオーバーロードを導入できることを知っています0と手動でbar(foo<const T>)にディスパッチしますが、可能であれば重複を避けたいと思います。

+0

作品罰金(BCC32) ideone.comではC++ 14を使用していません( 'types 'const T'と 'int'には互換性のないcv-qualifier'があります)。 –

+0

それは私だけか、あなたはその逆でしたか?コピーc-torは 'remove_const'を使います。あなたの記述と' bar'を使うコードは** ** const **を追加する場合です。 –

+0

@ YehezkelB: 'foo 'は 'foo 'から構築可能でなければならないので、コンストラクタの引数の 'const'を削除する必要があります。私は*書くと正しいと思う。 –

答えて

5

理由があります。その場合、foo<int>は実際にはfoo<const T>と一致せず、コンパイラはTが何であるかを推測することができません。あなたは、直接型を指定チェックするために自分で試すことができます:あなたは何ができるか

int main() 
{ 
    bar(foo<const int>()); // fine 
    bar<int>(foo<int>()); // also fine 
} 

は、コンパイラは任意の型を取るようにすることです:

template <typename T> // T might be foo<int> 
void bar(T f) { } 

それともたい場合は、コンパイラを推論をさせることができますconstなしインナーT

template <typename T> // can deduce T as const int 
void bar(foo<T> f) { } 

あなたは本当に、あなたのクラスにユーティリティ関数を追加したい場合があります(でも、汎用コードで)const性を強制したい場合は、このような何か:あなたは一般的な機能を使用するときに、あなたが送ることができる

foo<const T> as_const() const { return *this; } 

は、あなたのクラスのconstのバージョンである:私の前のC++ 11コンパイラに示したように、私にとって

​​
+0

テンプレート関数を呼び出すコンテキストでは、テンプレート引数の型を明示的に指定するのが便利です。私のアプリケーションでも同様に動作します。 –

+0

関数を乱雑にするのではなく、テンプレートの引数型を指定すると、テンプレートエイリアスを定義して、クラスfooがインスタンス化された 'T'を取得できます。 –

6

テンプレートではコンバージョンが許可されていません。

あなたが書いた:

template <typename T> 
void bar(foo<const T> f) { } 

barはどのTため、foo<const T>を受け入れます。それは何も受け入れません。 foo<int>foo<const int>に変換されても問題はありません。その変換は決して考慮されません。完全停止。

あなたはconstとして受け取っfを扱いたい場合は、条件付きでそれconst行うことができます:暗黙的な変換は、テンプレート引数控除した後に適用されるので、あなたは、コードが動作しない

// convert this version 
template <class T> foo<T const> make_const_f(foo<T> const& rhs) { return {rhs}; }  
// pass this version through 
template <class T> foo<T const>& make_const_f(foo<T const>& rhs) { return rhs; } 

template <typename T> 
void bar(foo<T> f) { 
    auto&& const_f = make_const_f(f); 

    // if T was const, const_f is a reference to f 
    // if T wasn't const, const_f is a new object of type foo<T const> 
} 
+0

'std'に対して' as_const'が提案されているので、異なるセマンティクスを持つフリー関数を作成することは悪い考えです。 – Yakk

+0

@Yakkええ、命名は難しいです。 – Barry

+2

プログラミングには2つの難しいことがあります。名前を付けること、キャッシュすること、そして1つずつのエラー。 – Yakk

関連する問題