【问题标题】:const change without const_cast<> Why no compiler warning/error?没有 const_cast<> 的 const 更改 为什么没有编译器警告/错误?
【发布时间】:2018-07-19 05:47:21
【问题描述】:

演示问题的代码示例:

#include <functional>
#include <set>

void useCallback(std::function<void(char *)> callback)
{
}

int main()
{
    std::function<void(char const *)> callback = [](char const *)
    {
    };

    useCallback(callback);

    return 0;
}

是的,const 删除在一天结束时是良性的,useCallback() 在其 API 中声明它准备接受并使用修改其参数的回调,所以它会做得很好没有的功能。

那么为什么阻止将std::set&lt;char *&gt; 传递给期望std::set&lt;char const *&gt; 的函数的参数在这里不适用?该论点正确地指出 char *char const * 是不同的类型,因此这两个集合不是类型等价的。

记住这一点,为什么callback 的类型和useCallback() 的参数没有被认为不同?

-- 编辑--

这是使用 MSVC,VS 2017。

【问题讨论】:

  • 你使用的是哪个编译器?
  • 这是使用 MSVC。我很想知道 GCC 的想法。
  • @dgnuff 你可以在gcc.godbolt.org在线试用

标签: c++ constants language-lawyer


【解决方案1】:

该论点正确地指出char *char const * 是不同的类型,因此这两个集合不是类型等价的。

std::function&lt;void(char *)&gt;std::function&lt;void(char const *)&gt; 也是不同的类型,因此这两个函数对象不是类型等价的。只是与std::set 不同,它们不需要是类型等价的!​​p>

std::function&lt;void(char *)&gt; 有一个构造函数,它可以接受任何可以用char * 参数调用的对象。 std::function&lt;void(char const *)&gt; 可以用 char * 参数调用,所以没问题。从 lambda 初始化 std::function&lt;T&gt; 时使用的构造函数是相同的:类型也不同,但只要在传递 T 中的参数类型时可以调用 lambda,就可以接受。

【讨论】:

  • 当然,如果我通过引用将参数带到useCallback(),它确实会失败。
  • std::function&lt;void(char *)&gt; 会将完整的std::function&lt;void(char const *)&gt; 存储为目标吗?在 cppreference 上阅读此内容时,它似乎会将完整的 std::function 移动到目标 std::function 的目标中,而不仅仅是目标
  • 啊,用target() 函数搞定了。事实上,std::function 对象是“堆叠的”并且没有应用转换(例如在 unique_ptr 构造函数中)
【解决方案2】:

这里没有问题。 const 实际上并没有被丢弃在这里,因为使用适合 std::function&lt;void(char *)&gt; 的参数调用 std::function&lt;void(char const *)&gt; 函数(即提供 char * 参数)非常好。错误的情况是相反的情况:

void useCallback(std::function<void(char const *)> callback)
{
}

int main()
{
    std::function<void(char *)> callback = [](char *)
    {
    };

    useCallback(callback);

    return 0;
}

std::function&lt;void(char *)&gt; 不能使用适合std::function&lt;void(char const *)&gt; 调用的参数调用。因此std::function&lt;void(char const *)&gt;函数对象的构造函数应该产生错误。

【讨论】:

    【解决方案3】:

    现有的答案很好地解释了为什么这是完全合法的原因以及与std::set 参数的区别是什么,我想提供一个示例来证明类型安全不会丢失。考虑一下这个

    void useCallback(std::function<void(char *)> callback)
    {
        callback("abc");
    }
    

    这将编译,尽管它会将字符串文字转换为const char*,这会通过 clang 和 gcc 为您提供适当的警告。这不编译:

    void useCallback(std::function<void(char *)> callback)
    {
        const char *str = "abc";
    
        callback(str);
    }
    

    std::function&lt;void(char const *)&gt; 的原始签名因此仍然存在并由编译器很好地维护。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-09
      • 2018-02-16
      • 1970-01-01
      • 2014-06-19
      • 1970-01-01
      • 2011-03-03
      • 1970-01-01
      相关资源
      最近更新 更多