您可以使用关键字显式来阻止方法参数的自动转换吗?

时间:2008-10-06 18:58:03

标签: c++ implicit-conversion explicit

我知道您可以将C ++关键字'explicit'用于类的构造函数,以防止类型的自动转换。您是否可以使用相同的命令来阻止类方法的参数转换?

我有两个类成员,一个将bool作为参数,另一个是unsigned int。当我用int调用函数时,编译器将param转换为bool并调用错误的方法。我知道最终我会替换bool,但是现在不想破坏其他例程,因为这个新例程已经开发出来了。

8 个答案:

答案 0 :(得分:62)

不,你不能使用显式,但你可以这样做:

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);
};

对于采用boolunsigned int的每个方法重复此模式。不要为方法的模板化版本提供实现。

这将强制用户始终显式调用bool或unsigned int版本。

任何使用Methodbool以外的类型调用unsigned int的尝试都将无法编译,因为该成员是私有的,当然,受可见性规则的标准例外限制(朋友,内部电话等)。如果具有访问权限的东西调用私有方法,则会出现链接器错误。

答案 1 :(得分:14)

没有。 explicit阻止特定类之间的自动转换,无论上下文如何。当然,你无法为内置类做到这一点。

答案 2 :(得分:7)

以下是一个非常基本的包装器,可用于创建强大的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
}

这种方法的一个很好的特点是,您还可以区分具有相同类型的不同参数。例如,您可以拥有以下内容:

class WidthTag;
typedef StrongType<int, WidthTag> Width;  
class HeightTag;
typedef StrongType<int, HeightTag> Height;  

void foo (Width width, Height height);

'foo'的客户会清楚哪个参数是哪个。

答案 3 :(得分:2)

可能对您有用的是使用模板。以下显示专门用于foo<>()boolunsigned int的模板函数intmain()函数显示调用的解析方式。请注意,使用未指定类型后缀的常量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);
}

答案 4 :(得分:1)

当前接受的answer(使用私有模板函数)很好,但是已经过时了。在C ++ 11中,我们可以改用delete d函数:

#include <iostream>

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

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

int main() {
    Thing t;
    int int_value = 1;
    size_t size_t_value = 2;

    t.Foo(int_value);

    // t.Foo(size_t_value);  // fails with below error
    // error: use of deleted function
    //   ‘void Thing::Foo(T) [with T = long unsigned int]’

    return 0;
}

这会更直接地传达源代码的意图,并在尝试使用具有不允许的参数类型的功能时为用户提供更清晰的错误消息。

答案 5 :(得分:0)

编译器发出“模糊呼叫”警告,这就足够了。

我正在进行TDD开发,并没有意识到我忘了在模拟对象中实现相应的调用。

答案 6 :(得分:0)

bool是一个限制为0或1的int。这是return 0的整个概念;它在逻辑上与返回false相同;(不要在代码中使用它)。

答案 7 :(得分:-1)

你也可以写一个调用bool的int版本。