Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何避免非构造函数上的隐式转换?_C++_Function_Casting_Implicit Conversion - Fatal编程技术网

C++ 如何避免非构造函数上的隐式转换?

C++ 如何避免非构造函数上的隐式转换?,c++,function,casting,implicit-conversion,C++,Function,Casting,Implicit Conversion,如何避免对非构造函数进行隐式转换? 我有一个以整数作为参数的函数, 但该函数也将接受字符、布尔和长字符。 我相信它通过隐式地铸造它们来实现这一点。 如何避免这种情况,使函数只接受匹配类型的参数,否则将拒绝编译? 有一个关键字“explicit”,但它不适用于非构造函数:\ 我该怎么办 以下程序已编译,但我不希望它: #include <cstdlib> //the function signature requires an int void function(int i); i

如何避免对非构造函数进行隐式转换?
我有一个以整数作为参数的函数,
但该函数也将接受字符、布尔和长字符。
我相信它通过隐式地铸造它们来实现这一点。
如何避免这种情况,使函数只接受匹配类型的参数,否则将拒绝编译?
有一个关键字“explicit”,但它不适用于非构造函数:\
我该怎么办

以下程序已编译,但我不希望它:

#include <cstdlib>

//the function signature requires an int
void function(int i);

int main(){

    int i{5};
    function(i); //<- this is acceptable

    char c{'a'};
    function(c); //<- I would NOT like this to compile

    return EXIT_SUCCESS;
}

void function(int i){return;}
#包括
//函数签名需要一个int
空洞函数(inti);
int main(){
int i{5};

函数(i);//不能直接使用,因为
char
会自动升级为
int

不过,您可以使用一个技巧:创建一个以
char
为参数的函数,但不要实现它。它将编译,但您将得到一个链接器错误:

void function(int i) 
{
}
void function(char i);
//or, in C++11
void function(char i) = delete;
使用
char
参数调用函数将中断生成


术语:非构造函数?您是指非构造函数的函数吗?

定义与所有其他类型匹配的函数模板:

void function(int); // this will be selected for int only

template <class T>
void function(T) = delete; // C++11 
这是C++03的方式:

// because this ugly code will give you compilation error for all other types
class DeleteOverload
{
private:
    DeleteOverload(void*);
};


template <class T>
void function(T a, DeleteOverload = 0);

void function(int a)
{}
//因为这段难看的代码会给您所有其他类型的编译错误
类删除重载
{
私人:
删除过载(无效*);
};
模板
无效函数(T a,DeleteOverload=0);
虚函数(INTA)
{}

也许可以使用struct将第二个函数设为私有函数:

#include <cstdlib>

struct NoCast {
    static void function(int i);
  private:
    static void function(char c);
};

int main(){

    int i(5);
    NoCast::function(i); //<- this is acceptable

    char c('a');
    NoCast::function(c); //<- Error

    return EXIT_SUCCESS;
}

void NoCast::function(int i){return;}

这里有一个通用的解决方案,如果用int以外的任何东西调用
函数
,就会在编译时导致错误

template <typename T>
struct is_int { static const bool value = false; };

template <>
struct is_int<int> { static const bool value = true; };


template <typename T>
void function(T i) {
  static_assert(is_int<T>::value, "argument is not int");
  return;
}

int main() {
  int i = 5;
  char c = 'a';

  function(i);
  //function(c);

  return 0;
}
模板
结构是{static const bool value=false;};
模板
结构是{static const bool value=true;};
模板
空洞函数(T i){
静态_断言(is_int::value,“参数不是int”);
返回;
}
int main(){
int i=5;
字符c='a';
功能(i);
//职能(c);
返回0;
}

它的工作原理是允许参数使用任何类型,但将
is_int
用作类型级谓词。
is_int
的泛型实现有一个假值,但int类型的显式专门化有一个真值,因此静态断言保证参数的类型正好是
int
有一个编译错误。

< p> >我将用下面的代码回答这个问题,但是即使它与VisualC++一起工作,在产生所需编译错误的意义上,MinGW g +4.4.7.1接受它,并调用rValor引用构造函数!

我认为这一定是一个编译器错误,但我可能是错的,所以-有人吗

无论如何,下面是代码,它可能是一个符合标准的解决方案(或者,它可能是我的thinko!):

#包括
#include//std::是否相同,std::如果
使用名称空间std;
模板<类类型>
结构盒
{
类型值;
模板
盒装(
Arg const&v,
如果::value,Arg>::Type*=0,则启用typename
)
:值(v)
{
wcout对于C++14(我相信是C++11),也可以通过重载右值引用来禁用复制构造函数:

例如: 假设您有一个base
Binding
类,其中
C
是base
Constraint
类或继承的类。假设您将
Binding
按值存储在一个向量中,您将引用传递给绑定,并希望确保不会导致隐式复制

您可以通过删除右值引用特定情况下的
func(Binding&&x)
(根据PiotrNycz的示例)来执行此操作

片段:

template<typename T>
void overload_info(const T& x) {
  cout << "overload: " << "const " << name_trait<T>::name() << "&" << endl;
}

template<typename T>
void overload_info(T&& x) {
  cout << "overload: " << name_trait<T>::name() << "&&" << endl;
}

template<typename T>
void disable_implicit_copy(T&& x) = delete;

template<typename T>
void disable_implicit_copy(const T& x) {
  cout << "[valid] ";
  overload_info<T>(x);
}

...

int main() {
  Constraint c;
  LinearConstraint lc(1);

  Binding<Constraint> bc(&c, {});
  Binding<LinearConstraint> blc(&lc, {});

  CALL(overload_info<Binding<Constraint>>(bc));
  CALL(overload_info<Binding<LinearConstraint>>(blc));

  CALL(overload_info<Binding<Constraint>>(blc));

  CALL(disable_implicit_copy<Binding<Constraint>>(bc));
  // // Causes desired error
  // CALL(disable_implicit_copy<Binding<Constraint>>(blc));
}

完整的源代码:

我首先尝试了PiotrNycz的方法(对于C++03,我被迫在项目中使用),然后我尝试找到一种更通用的方法,并提出了这个ForcedType模板类

模板
结构强制类型{
强制类型(tv):m_v(v){}
运算符T&({return m_v;}
运算符常量T&()常量{return m_v;}
私人:
模板
强制型(T2);
T m_v;
};
模板
结构强制类型{
强制类型(常量T&v):m_v(v){}
运算符常量T&()常量{return m_v;}
私人:
模板
强制类型(常数T2&);
康斯特T&m_v;
};
模板
结构强制类型{
强制类型(T&v):m_v(v){}
运算符T&({return m_v;}
运算符常量T&()常量{return m_v;}
私人:
模板
强制型(T2&);
T&m_v;
};
如果我没有弄错的话,这三个专门化应该涵盖所有常见的用例。我不确定是否确实需要对右值引用(在C++11以后)进行专门化,或者一个by值就足够了

如果函数有3个参数,而第3个参数不允许隐式转换,则可以这样使用:

函数(ParamType1 param1,ParamType2 param2,ForcedType param3);
8年后(C++20之前版本,请参见编辑): 如果您不介意使用模板函数(您可能会介意),最现代的解决方案是在
std::enable>和
std::is_相同的情况下使用模板函数

即:

//我们只想取int
模板
无效函数(T x){
}
编辑(c++20) 我最近改用了c++20,我相信有更好的方法。如果您的团队或您不使用c++20,或者不熟悉新的概念库,请不要使用它。这是更好的方法,正如新的c++20标准以及新功能的作者所概述的那样(阅读比亚恩·斯特劳斯图普撰写的论文

模板
要求标准::与(T,int)相同
无效函数(T x){
//...
}
小编辑(概念的不同模式) 下面是一个更好的方法,因为它解释了你的理由,有一个显式的int
prog.cpp: In function ‘int main()’:
prog.cpp:7: error: ‘static void NoCast::function(char)’ is private
prog.cpp:16: error: within this context
template <typename T>
struct is_int { static const bool value = false; };

template <>
struct is_int<int> { static const bool value = true; };


template <typename T>
void function(T i) {
  static_assert(is_int<T>::value, "argument is not int");
  return;
}

int main() {
  int i = 5;
  char c = 'a';

  function(i);
  //function(c);

  return 0;
}
#include <iostream>
#include <utility>      // std::is_same, std::enable_if
using namespace std;

template< class Type >
struct Boxed
{
    Type value;

    template< class Arg >
    Boxed(
        Arg const& v,
        typename enable_if< is_same< Type, Arg >::value, Arg >::type* = 0
        )
        : value( v )
    {
        wcout << "Generic!" << endl;
    }

    Boxed( Type&& v ): value( move( v ) )
    {
        wcout << "Rvalue!" << endl;
    }
};

void function( Boxed< int > v ) {}

int main()
{
    int i = 5;
    function( i );  //<- this is acceptable

    char c = 'a';
    function( c );  //<- I would NOT like this to compile
}
template<typename T>
void overload_info(const T& x) {
  cout << "overload: " << "const " << name_trait<T>::name() << "&" << endl;
}

template<typename T>
void overload_info(T&& x) {
  cout << "overload: " << name_trait<T>::name() << "&&" << endl;
}

template<typename T>
void disable_implicit_copy(T&& x) = delete;

template<typename T>
void disable_implicit_copy(const T& x) {
  cout << "[valid] ";
  overload_info<T>(x);
}

...

int main() {
  Constraint c;
  LinearConstraint lc(1);

  Binding<Constraint> bc(&c, {});
  Binding<LinearConstraint> blc(&lc, {});

  CALL(overload_info<Binding<Constraint>>(bc));
  CALL(overload_info<Binding<LinearConstraint>>(blc));

  CALL(overload_info<Binding<Constraint>>(blc));

  CALL(disable_implicit_copy<Binding<Constraint>>(bc));
  // // Causes desired error
  // CALL(disable_implicit_copy<Binding<Constraint>>(blc));
}
>>> overload_info(bc)
overload: T&&

>>> overload_info<Binding<Constraint>>(bc)
overload: const Binding<Constraint>&

>>> overload_info<Binding<LinearConstraint>>(blc)
overload: const Binding<LinearConstraint>&

>>> overload_info<Binding<Constraint>>(blc)
implicit copy: Binding<LinearConstraint>  ->  Binding<Constraint>
overload: Binding<Constraint>&&

>>> disable_implicit_copy<Binding<Constraint>>(bc)
[valid] overload: const Binding<Constraint>&
cpp_quick/prevent_implicit_conversion.cc:116:8: error: call to deleted function 'disable_implicit_copy'
  CALL(disable_implicit_copy<Binding<Constraint>>(blc));
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template <class T>
    requires std::same_as(T,int)
void func(T x) {
    //...
}
template <class T>
concept explicit_int = std::same_as<T,int>;

template <explicit_int T>
void func(T x) {

}
template <class T>
concept explicit_int = std::same_as<T,int>;

void func(explicit_int auto x) {

}