web-dev-qa-db-ja.com

キーワードexplicitを使用して、メソッドパラメータの自動変換を防ぐことはできますか?

クラスのコンストラクターにC++キーワード「explicit」を使用して、型の自動変換を防ぐことができることを私は知っています。これと同じコマンドを使用して、クラスメソッドのパラメーターの変換を防ぐことができますか?

2つのクラスメンバーがあります。1つはboolをパラメーターとして受け取り、もう1つはunsignedintです。 intを使用して関数を呼び出すと、コンパイラーがparamをboolに変換し、間違ったメソッドを呼び出しました。最終的にブール値を置き換えることはわかっていますが、この新しいルーチンが開発されているので、今のところ他のルーチンを壊したくありません。

51
Superpolock

いいえ、明示的に使用することはできませんが、代わりにこれを行うことができます。

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またはunsignedintバージョンを明示的に呼び出す必要があります。

Methodまたはunsigned int以外のタイプでboolを呼び出そうとすると、メンバーはプライベートであるためコンパイルに失敗します。もちろん、可視性ルールの標準的な例外が適用されます(友人、内部呼び出しなど)。アクセス権のあるものがプライベートメソッドを呼び出すと、リンカーエラーが発生します。

65

いいえ。explicitは、コンテキストに関係なく、特定のクラス間の自動変換を防ぎます。そしてもちろん、組み込みクラスではそれを行うことはできません。

14
Lev

以下は、強力な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'のクライアントには、どの引数がどれであるかが明確になります。

7
Richard Corden

あなたのために働くかもしれない何かはテンプレートを使うことです。以下は、bool、_unsigned int_、およびintに特化したテンプレート関数foo<>()を示しています。 main()関数は、呼び出しがどのように解決されるかを示します。タイプサフィックスを指定しない定数intを使用する呼び出しは、foo<int>()に解決されるため、foo( 1)を呼び出すとエラーが発生することに注意してください。 intに特化しないでください。この場合、リテラル整数定数を使用する呼び出し元は、_"U"_サフィックスを使用して、呼び出しを解決する必要があります(これは必要な動作である可能性があります)。

それ以外の場合は、intに特化し、_"U"_サフィックスを使用するか、_unsigned int_バージョンに渡す前に_unsigned int_にキャストする必要があります(または、必要に応じて、値が負ではないことを表明します)。

_#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);
}
_
2
Michael Burr

bool IS 0または1のいずれかに制限されるint。これがreturn0の概念全体です。論理的にはreturnfalseと言うのと同じです;(コードでこれを使用しないでください)しかし)。

0
WolfmanDragon

コンパイラは「あいまいな呼び出し」の警告を出しましたが、これで十分です。

私はTDD開発を行っていましたが、対応する呼び出しをモックオブジェクトに実装するのを忘れていることに気づきませんでした。

0
Superpolock