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

Tre*_*key 36 c++ casting function implicit-cast implicit-conversion

如何避免对非构造函数进行隐式转换?
我有一个函数,它接受一个整数作为参数,
但该函数也将采用字符,bools和long.
我相信它是通过隐式地施放它来实现的.
如何避免这种情况,以便函数只接受匹配类型的参数,否则将拒绝编译?
有一个关键字"显式"但它不适用于非构造函数.:\
我该怎么办?

以下程序编译,虽然我不喜欢:

#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;}
Run Code Online (Sandbox Code Playgroud)

*请务必指出任何滥用术语和假设的行为

Pio*_*ycz 44

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

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

template <class T>
void function(T) = delete; // C++11 
Run Code Online (Sandbox Code Playgroud)

这是因为始终首先考虑具有直接匹配的非模板函数.然后考虑具有直接匹配的函数模板 - 因此永远function<int>不会使用.但是对于其他任何东西,比如char,function<char>都会被使用 - 这会给你的编译错误:

void function(int) {}

template <class T>
void function(T) = delete; // C++11 


int main() {
   function(1);
   function(char(1)); // line 12
} 
Run Code Online (Sandbox Code Playgroud)

错误:

prog.cpp: In function 'int main()':
prog.cpp:4:6: error: deleted function 'void function(T) [with T = char]'
prog.cpp:12:20: error: used here
Run Code Online (Sandbox Code Playgroud)

这是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)
{}
Run Code Online (Sandbox Code Playgroud)


Luc*_*ore 20

你不能直接,因为一个char自动升级到int.

您可以采用一种技巧:创建一个带有charas参数但不实现它的函数.它会编译,但你会得到一个链接器错误:

void function(int i) 
{
}
void function(char i);
//or, in C++11
void function(char i) = delete;
Run Code Online (Sandbox Code Playgroud)

使用char参数调用函数将破坏构建.

请参见http://ideone.com/2SRdM

术语:非构造函数?你的意思是一个不是构造函数的函数吗?

  • 由于OP使用C++ 11,我们可以`=删除它'并获得[编译错误](http://ideone.com/1tND3),而不是链接器错误. (16认同)

Hun*_*ler 10

8 年后(PRE-C++20,见编辑):

如果您不介意模板函数(您可能会介意),最现代的解决方案是使用带有std::enable_if和的模板化函数std::is_same

即:

// Where we want to only take int
template <class T, std::enable_if_t<std::is_same<T,int>,bool> = false>
void func(T x) {
    
}
Run Code Online (Sandbox Code Playgroud)

编辑 (c++20)

我最近切换到 c++20,我相信有更好的方法。如果您的团队或者您不使用 c++20,或者不熟悉新概念库,请不要使用它。这更好,并且是新的 c++20 标准中概述的预期方法,以及新功能的作者(阅读 Bjarne Stroustrup在这里撰写的论文。

template <class T>
    requires std::same_as(T,int)
void func(T x) {
    //...
}
Run Code Online (Sandbox Code Playgroud)

小编辑(概念的不同模式)

下面是一个更好的方法,因为它解释了你的原因,有一个显式的 int。如果你经常这样做,并且想要一个好的模式,我会做以下事情:

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

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

}
Run Code Online (Sandbox Code Playgroud)

小编辑2(我保证的最后一个)

还有一种实现这种可能性的方法:

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

void func(explicit_int auto x) {

}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢。我现在将其切换为已接受的答案。 (2认同)

Geo*_*edy 7

这是一个通用的解决方案,如果function使用除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;
}
Run Code Online (Sandbox Code Playgroud)

它的工作原理是允许参数的任何类型起作用,但is_int用作类型级谓词.泛型实现is_int具有false值,但int类型的显式特化值为true,因此静态断言保证参数具有完全类型,int否则存在编译错误.