明示的なキーワードを使用して、メソッドパラメータの自動変換を防止できますか?
-
05-07-2019 - |
質問
型の自動変換を防ぐために、クラスのコンストラクターにC ++キーワード「明示的」を使用できることを知っています。この同じコマンドを使用して、クラスメソッドのパラメーターの変換を防止できますか?
2つのクラスメンバがあります。1つはブール値をパラメータとして受け取り、もう1つは符号なしintです。 intで関数を呼び出すと、コンパイラーはparamをboolに変換し、間違ったメソッドを呼び出しました。最終的にブールを置き換えることはわかっていますが、現時点では、この新しいルーチンが開発されているため、他のルーチンを壊したくないです。
解決
いいえ、明示的に使用することはできませんが、代わりにこれを行うことができます:
class ClassThatOnlyTakesBoolsAndUIntsAsArguments
{
public:
void Method(bool arg1);
void Method(unsigned int arg1);
// Below just an example showing how to do the same thing with more arguments
void MethodWithMoreParms(bool arg1, SomeType& arg2);
void MethodWithMoreParms(unsigned int arg1, SomeType& arg2);
private:
template<typename T>
void Method(T arg1);
// Below just an example showing how to do the same thing with more arguments
template<typename T>
void MethodWithMoreParms(T arg1, SomeType& arg2);
};
bool
またはunsigned int
をとるすべてのメソッドに対してこのパターンを繰り返します。メソッドのテンプレート化バージョンの実装を提供しないでください。
これにより、ユーザーはboolまたはunsigned intバージョンを常に明示的に呼び出すように強制されます。
Method
または<=>以外のタイプで<=>を呼び出そうとすると、メンバーはプライベートであるため、コンパイルに失敗します。もちろん、可視性ルールの標準例外(友人、内部呼び出しなど) 。)。アクセスできるものがprivateメソッドを呼び出すと、リンカーエラーが発生します。
他のヒント
いいえ。 explicit
は、コンテキストに関係なく、特定のクラス間の自動変換を防ぎます。そしてもちろん、組み込みクラスに対してはできません。
以下は、強力なtypedefを作成するために使用できる非常に基本的なラッパーです。
template <typename V, class D>
class StrongType
{
public:
inline explicit StrongType(V const &v)
: m_v(v)
{}
inline operator V () const
{
return m_v;
}
private:
V m_v; // use V as "inner" type
};
class Tag1;
typedef StrongType<int, Tag1> Tag1Type;
void b1 (Tag1Type);
void b2 (int i)
{
b1 (Tag1Type (i));
b1 (i); // Error
}
このアプローチの優れた機能の1つは、同じタイプの異なるパラメーターを区別できることです。たとえば、次のものがあります。
class WidthTag;
typedef StrongType<int, WidthTag> Width;
class HeightTag;
typedef StrongType<int, HeightTag> Height;
void foo (Width width, Height height);
「foo」のクライアントには、どの引数がどれであるかが明確になります。
あなたのために働くかもしれない何かは、テンプレートを使用することです。以下は、foo<>()
、bool
、およびunsigned int
に特化したテンプレート関数int
を示しています。 main()
関数は、呼び出しが解決される方法を示します。型接尾辞を指定しない定数foo<int>()
を使用する呼び出しはfoo( 1)
に解決されるため、"U"
に特化していない場合は<=>の呼び出しエラーが発生することに注意してください。この場合、リテラル整数定数を使用する呼び出し元は、<=>接尾辞を使用して解決する呼び出しを取得する必要があります(これが目的の動作である可能性があります)。
それ以外の場合は、<=>に特化して、<=>接尾辞を使用するか、<=>にキャストしてから<=>バージョンに渡す必要があります(または、値がそうではないことをアサートします) tネガティブ、それがあなたの望むものなら)。
#include <stdio.h>
template <typename T>
void foo( T);
template <>
void foo<bool>( bool x)
{
printf( "foo( bool)\n");
}
template <>
void foo<unsigned int>( unsigned int x)
{
printf( "foo( unsigned int)\n");
}
template <>
void foo<int>( int x)
{
printf( "foo( int)\n");
}
int main ()
{
foo( true);
foo( false);
foo( static_cast<unsigned int>( 0));
foo( 0U);
foo( 1U);
foo( 2U);
foo( 0);
foo( 1);
foo( 2);
}
コンパイラは<!> quot; ambiguous call <!> quot;を出しました。警告、これで十分です。
TDD開発を行っていましたが、対応する呼び出しをモックオブジェクトに実装するのを忘れたことに気付きませんでした。
boolは0または1に制限されるintです。これはreturn 0;の概念全体です。論理的にはreturn false;と言うのと同じです(ただし、コードではこれを使用しないでください)。
boolを呼び出すintバージョンを記述することもできます。