【问题标题】:Why does we have a type mismatch?为什么我们有类型不匹配?
【发布时间】:2019-01-30 15:32:41
【问题描述】:

我写了一个程序来看看,字符串字面量是如何在模板函数中推导出来的。

#include <iostream>
#include <string>
#include <type_traits>

template<typename T> void passByValue(T by_value)
{
    std::cout << std::is_same_v<char const*, decltype(by_value)> << std::endl; // okay
}

template<typename T> void passByReferance(T &by_ref)
{
    std::cout << std::is_same_v<char const*, std::remove_reference_t<decltype(by_ref)>> << std::endl;
}

template<typename T> void passByConstRef(const T &const_ref)
{
    std::cout << std::is_same_v<char const*, std::remove_const_t<std::remove_reference_t<decltype(const_ref)>>> << std::endl;
}

int main()
{
    std::cout << std::boolalpha;
    passByValue("string");    // true: good
    passByReferance("string");// false ??
    passByConstRef("string"); // false ??
    return 0;
}

事实证明,只有 passByValue 的字符串字面量才推导出为 const char* 类型。

在其他两种情况下(passByReferencepassByConstRef),如果我们应用到推导的参数 std::remove_reference_tstd::remove_const_t,我想得到的是const char*,对吗?

当我使用 std::decay_t 进行完全衰减时得到类型匹配,这是为什么呢?

【问题讨论】:

  • 答案涵盖了所有细节。如果您需要更好地了解类型,可以在此处使用帮助程序:godbolt.org/z/AqTA0e
  • @balki 太好了:您的代码演示了机器的视图。你能把它贴在答案部分吗?至少我可以给你竖起大拇指。

标签: c++ templates type-deduction


【解决方案1】:

您传递的是const char[7] 而不是const char *。数组和指针不是一回事。他们经常感到困惑,因为数组很容易衰减为指向其第一个元素的指针。当通过引用获取时,数组不需要衰减为指针。只有在第一种情况下,您的数组才需要衰减为指针。

以下测试为每种情况生成true

#include <iostream>
#include <string>
#include <type_traits>

template<typename T> void passByValue(T by_value)
{
    std::cout << std::is_same_v<char const*, decltype(by_value)> << std::endl; 
}

template<typename T> void passByReferance(T &by_ref)
{
    std::cout << std::is_same_v<char const[7], std::remove_reference_t<decltype(by_ref)>> << std::endl;
}

template<typename T> void passByConstRef(const T &const_ref)
{
    std::cout << std::is_same_v<char [7], std::remove_const_t<std::remove_reference_t<decltype(const_ref)>>> << std::endl;
}

int main()
{
    std::cout << std::boolalpha;
    passByValue("string");    
    passByReferance("string");
    passByConstRef("string"); 
    return 0;
}

编辑:至于std::decay,它显式导致数组类型衰减为指针:

如果T 将类型命名为“U 的数组”或“引用U 的数组”,则成员 typedef 类型为U*

【讨论】:

  • 那么在applying std::decay_t的情况下会发生什么
  • @JoeyMallone 不要使用普通数组,您永远不必担心这一点。 std::arraystd::string/std::string_view 应该足够了。
  • @MaxLanghof,是的,谢谢。我每天都在这里学到新东西。
  • @Const 将我的评论移至答案。
  • @FrançoisAndrieux 是的,没错,我一直认为std::decay 使它成为const char*,但我使用的不是。这澄清了我的疑问。谢谢。
【解决方案2】:

一些帮助更好地了解类型。行政长官:https://godbolt.org/z/6EFmIR

#include <type_traits>

template<class T>
struct Tis { Tis(); };

template<bool b>
struct Truth{ Truth(); };

template<typename T> void passByValue(T by_value)
{
    Tis<T>{}; //call    Tis<char const*>::Tis()
    Truth<
        std::is_same_v<char const*, decltype(by_value)>
    >{}; // call    Truth<true>::Truth()
}

template<typename T> void passByReferance(T &by_ref)
{
    Tis<T>{}; // call    Tis<char const [7]>::Tis()
    Tis<decltype(by_ref)>{}; // call    Tis<char const (&) [7]>::Tis()
    Truth<
        std::is_same_v<char const*, std::remove_reference_t<decltype(by_ref)>> 
    >{}; // call    Truth<false>::Truth()
    Tis<
        std::remove_reference_t<decltype(by_ref)>
    >{}; // call    Tis<char const [7]>::Tis()
}

template<typename T> void passByConstRef(const T &const_ref)
{
    Tis<T>{}; // call    Tis<char [7]>::Tis()
    Truth<
        std::is_same_v<char const*, std::remove_const_t<std::remove_reference_t<decltype(const_ref)>>> 
    >{}; // call    Truth<false>::Truth()
    Tis<
        std::remove_const_t<std::remove_reference_t<decltype(const_ref)>>
    >{}; // call    Tis<char [7]>::Tis()
}

void foo1(){
    passByValue("string");
}
void foo2() {
    passByReferance("string");
}
void foo3() {
    passByConstRef("string");
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-13
    • 2022-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-04
    • 1970-01-01
    • 2010-10-09
    相关资源
    最近更新 更多