55

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

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

4

8 に答える 8

72

いいえ、明示的に使用することはできませんが、テンプレート化された関数を使用して、不適切なパラメーターの型をキャッチできます。

C++11では、テンプレート化された関数をdeletedとして宣言できます。簡単な例を次に示します。

#include <iostream>

struct Thing {
    void Foo(int value) {
        std::cout << "Foo: value" << std::endl;
    }

    template <typename T>
    void Foo(T value) = delete;
};

パラメータを指定Thing::Fooして呼び出そうとすると、次のエラー メッセージが表示されます。size_t

error: use of deleted function
    ‘void Thing::Foo(T) [with T = long unsigned int]’

C++11 より前のコードでは、代わりに未定義のプライベート関数を使用して実現できます。

class ClassThatOnlyTakesBoolsAndUIntsAsArguments
{
public:
  // Assume definitions for these exist elsewhere
  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:
  // You can leave these undefined
  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);
};

この場合の欠点は、コードとエラー メッセージが明確でないことです。そのため、C++11 オプションが利用可能な場合はいつでも選択する必要があります。

boolまたはを取るすべてのメソッドに対して、このパターンを繰り返しますunsigned int。メソッドのテンプレート化されたバージョンの実装を提供しないでください。

これにより、ユーザーは常に bool または unsigned int バージョンを明示的に呼び出す必要があります。

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

于 2008-10-06T19:56:15.400 に答える
14

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

于 2008-10-06T19:17:14.403 に答える
8

以下は、強力な 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' のクライアントには明らかです。

于 2008-10-06T21:22:12.357 に答える
2

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

それ以外の場合は、サフィックスを特殊化しintて使用するか、バージョンに渡す前ににキャストする必要があります (または、必要に応じて、値が負ではないことをアサートする必要があります)。"U"unsigned intunsigned 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);
}
于 2008-10-06T21:04:59.223 に答える
0

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

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

于 2008-10-06T19:05:38.577 に答える
0

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

于 2008-10-06T19:51:54.567 に答える
-1

bool を呼び出す int バージョンを作成することもできます。

于 2008-10-06T19:14:30.897 に答える