为什么在C ++参数类型匹配中鼓励“文字”衰减为“ const char *”? [英] Why is `"literal"` encouraged to decay to `const char*` in C++ argument type match?

查看:83
本文介绍了为什么在C ++参数类型匹配中鼓励“文字”衰减为“ const char *”?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用c ++ 14中的重载运算符,并且尝试匹配两种类型的参数:any-old-const-char *和a-string-literal。



也就是说,我试图查看是否可以区分以下内容:

  const char *运行; 

 编译时间 

我写了下面的代码,如图所示,当我尝试 span>> literal 调用了 const char * 函数。



当我 #if 0 - const char * 版本,模板版本就可以了。



如果我更改模板版本以对 literal 采用右值引用(&&)参数,它将无法编译。 / p>

如果我添加 const char(& literal)[] 非模板版本,则<$ c $首选使用c> const char * 版本。删除const-char *版本,最好使用模板版本。



您能解释一下吗?特别是:


  1. 为什么 const char * const char(&)[N] ?

  2. 为什么 const char(&)[N] 优于 const char(&)[] (非模板)?

  3. 为什么 const char(&)[N] 无法编译?

  4. 是否存在捕获文字字符串的正确方法?

谢谢。

  #include< iostream> ; 
使用命名空间std;

#include< gsl / gsl>
#include< type_name.h ++>

template< unsigned N>
自动
运算符>>>>(gsl :: span< const char *,-1& spn,const char(&literal)[N])
-> gsl :: span< const char *,-1&
{
cout<< 数组:<<文字<<恩德尔
return spn;
}

自动
运算符>>>>>(gsl :: span< const char *,-1& sn,const char * literal)
-> ; gsl :: span< const char *,-1&
{
cout<< Got const-char *:<<文字<<恩德尔
return spn;
}
#if 0
#endif

int
main(int argc,const char * argv [])
{
auto spn = gsl :: span< const char *>(argv,argc);

cout<< type_name< decltype(spn)>()<<恩德尔// gsl :: span< const char *,-1>

cout<< type_name< decltype( literal)>()<<恩德尔// char const(&)[8]

cout<< type_name< decltype(( literal))>()<<恩德尔// char const(&)[8]

auto helpx = literal;
cout<< type_name< decltype(helpx)>()<<恩德尔// const char *


spn>> 文字; //获得const-char *:立即数

返回0;
}

编辑:



如果有问题,我正在使用:

  c ++ --std = c + +14 -Iinclude -c -o main.o main.c ++ 

c ++说:

  $ c ++ --version 
Apple LLVM版本8.0.0(clang-800.0.42.1)
目标:x86_64 -apple-darwin16.5.0
线程模型:posix
InstalledDir:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin


解决方案


为什么 const char * 优于 const char(&)[N]




<这样做的原因是相当技术性的。即使字符串文字从 const char [N] const char * 的衰减是一个转换,它也会下降归入左值转换类别,因此[over.ics.rank] / 3认为它与根本没有转换一样好。由于任何一个重载都需要不转换,因此非模板重载将获胜。


为什么 const char (&)[N] 优于 const char(&)[] (非模板)?


不可能将对未知边界数组的引用绑定到类型为已知边界数组的值。相反,对未知边界数组的引用只能绑定到本身就是未知边界数组的值。


为什么 const char(&)[N] 无法编译?


字符串文字是左值,所以我不确定为什么会期望它起作用。


是否有正确的方法来捕捉文字


您可以使用辅助函数模板,该函数使用转发引用捕获其自变量,以免破坏任何类型信息( const char * const char [N] ),然后使用模板专门化来分派类型。您可能还想使用SFINAE来确保除 const char * const char [N]以外的其他任何功能时都将其禁用。

  template< bool b> 
struct f_helper;

模板<>
struct f_helper< true> {
void do_it(const char *){
puts( pointer);
}
};

模板<>
struct f_helper< false> {
模板< std :: size_t N>
void do_it(const char(&)[N]){
printf(长度为%zd\n的数组,N);
}
};

模板< class T,class =类型名std :: enable_if< std :: is_same< char *,std :: decay_t< T>> :: value ||
std :: is_same< const char *,std :: decay_t< T> ::: value> :: type>
void f(T& s){
f_helper< std :: is_pointer< std :: remove_reference_t< T>> :: value> {}。do_it(s);
}

Coliru链接: http://coliru.stacked-crooked.com/a/0e9681868d715e87


I'm playing around with overloading operators in c++14, and I tried to match two types of arguments: any-old-const-char*, and a-string-literal.

That is, I'm trying to see if I can discriminate between:

const char * run_time;

and

"compile time"

I wrote the code below, and as shown, when I try span >> "literal" it invoked the const char* function.

When I #if 0-out the const char* version, the template version gets called just fine.

If I change the template version to take an rvalue-reference (&&) parameter for literal, it doesn't compile.

If I add a const char (&literal)[] non-template version, the const char* version is still preferred. Removing the const-char* version, the template version is preferred.

Can you explain this? In particular:

  1. Why is const char* preferred over const char (&)[N]?
  2. Why is const char (&)[N] preferred over const char (&)[] (non-template)?
  3. Why is const char (&&)[N] unable to compile?
  4. Is there a "right way" to capture literal strings?

Thanks.

#include <iostream>
using namespace std;

#include <gsl/gsl>
#include <type_name.h++>

template<unsigned N>
auto
operator>>(gsl::span<const char*,-1>& spn, const char (&literal)[N])
    -> gsl::span<const char*, -1>&
{
    cout << "Got array: " << literal << endl;
    return spn;
}

auto
operator>>(gsl::span<const char*,-1>& spn, const char *literal)
    -> gsl::span<const char*, -1>&
{
    cout << "Got const-char*: " << literal << endl;
    return spn;
}
#if 0
#endif

int
main(int argc, const char *argv[])
{
    auto spn = gsl::span<const char*>(argv, argc);

    cout << type_name<decltype(spn)>() << endl; // gsl::span<const char *, -1>

    cout << type_name<decltype("literal")>() << endl; // char const (&)[8]

    cout << type_name<decltype(("literal"))>() << endl; // char const (&)[8]

    auto helpx = "literal";
    cout << type_name<decltype(helpx)>() << endl; // const char *


    spn >> "literal"; // Got const-char*: literal

    return 0;
}

Edit:

In case it matters, I'm compiling with:

c++ --std=c++14 -Iinclude   -c -o main.o main.c++

And c++ says:

$ c++ --version
Apple LLVM version 8.0.0 (clang-800.0.42.1)
Target: x86_64-apple-darwin16.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

解决方案

Why is const char* preferred over const char (&)[N]?

The reason for this is rather technical. Even though the decay of a string literal from const char[N] to const char* is a conversion, it falls into the "lvalue transformation" category and is therefore considered by [over.ics.rank]/3 to be as good as no conversion at all. Since "no conversion" is required for either overload, the non-template overload wins.

Why is const char (&)[N] preferred over const char (&)[] (non-template)?

It is not possible to bind a reference to array of unknown bound to a value of type array of known bound. Instead, a reference to array of unknown bound can only be bound to values that are themselves arrays of unknown bound.

Why is const char (&&)[N] unable to compile?

A string literal is an lvalue so I'm not sure why you would expect this to work.

Is there a "right way" to capture literal strings?

You can use a helper function template that captures its argument using a forwarding reference so as to not destroy any type information (const char* versus const char[N]) then dispatch on the type using template specialization. You'll probably also want to use SFINAE to make sure it is disabled if anything other than a const char* or const char[N] is passed in. To wit,

template <bool b>
struct f_helper;

template <>
struct f_helper<true> {
    void do_it(const char*) {
        puts("pointer");
    }
};

template <>
struct f_helper<false> {
    template <std::size_t N>
    void do_it(const char (&)[N]) {
        printf("array of length %zd\n", N);
    }
};

template <class T, class = typename std::enable_if<std::is_same<char*, std::decay_t<T>>::value ||
                                                   std::is_same<const char*, std::decay_t<T>>::value>::type>
void f(T&& s) {
    f_helper<std::is_pointer<std::remove_reference_t<T>>::value>{}.do_it(s);
}

Coliru link: http://coliru.stacked-crooked.com/a/0e9681868d715e87

这篇关于为什么在C ++参数类型匹配中鼓励“文字”衰减为“ const char *”?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆