【问题标题】:Templated function with defaulted std::function parameter causes symbol [...] already defined具有默认 std::function 参数的模板函数导致符号 [...] 已定义
【发布时间】:2018-10-24 11:27:18
【问题描述】:

我刚刚遇到了一些奇怪的事情。 我想知道这是否是一个错误,如果不是,我希望有人能解释这个问题。

我的问题是,当我创建一个将std::function 作为默认参数的模板化函数时,我只能创建该函数的一个模板实例化,否则会出错。

考虑以下代码:

#include <functional>

template<bool B>
void wut(std::function<void()> f = []() {})
{
    f();
}

int main() {
    wut<false>(); // works
    wut<false>(); // still works
    wut<true>();  // error
    return 0;
}

https://ideone.com/VlVcUv

编译这段代码时出现以下错误:

{standard input}: Assembler messages:
{standard input}:28: Error: symbol `_ZNSt14_Function_base13_Base_managerIUlvE_E10_M_managerERSt9_Any_dataRKS3_St18_Manager_operation' is already defined
{standard input}:127: Error: symbol `_ZNSt17_Function_handlerIFbvEUlvE_E9_M_invokeERKSt9_Any_data' is already defined

【问题讨论】:

  • 直觉上我会说你不能拥有两个具有相同名称和相同签名的不同函数。另一方面,我不知道标准是否真的要求 wut&lt;true&gt;wut&lt;false&gt; 成为两个不同的功能(因此我删除了我的答案)
  • 本地我使用的是 GCC 7.3.0。我刚刚尝试使用 clang 6.0.0 进行编译,它可以工作。所以看来我偶然发现了一个 GCC 错误。
  • 无法使用 GCC 7.3.0 gcc.godbolt.org/z/dRSrUw 重现,否则使用最新版本的 GCC、Clang 和 MSVC,它可以正常编译。
  • 我也无法使用 GCC 6.3 进行复制(Ideone 说它正在使用)。很奇怪。
  • 嗯很有趣!我使用的精确编译器版本是 g++ (Ubuntu 7.3.0-27ubuntu1~18.04) 7.3.0

标签: c++ templates std-function


【解决方案1】:

这是一个 gcc 错误(在 7.3 版之后看起来已修复),我们可以通过查看 [expr.prim.lambda.capture]p9 部分看到这一点:

出现在默认参数中的 lambda 表达式不应 隐式或显式捕获任何实体。 [示例:

void f2() {
int i = 1;
void g1(int = ([i]{ return i; })()); // ill-formed
void g2(int = ([i]{ return 0; })()); // ill-formed
void g3(int = ([=]{ return i; })()); // ill-formed
void g4(int = ([=]{ return 0; })()); // OK
void g5(int = ([]{ return sizeof i; })()); // OK
}

——结束示例]

作为 IDEOne 的替代方案,您可以使用与 gcc 和 clang 版本保持同步的 Wandbox,请参阅 your example live there

【讨论】:

  • 我正要争辩说这些示例(g4 和 g5)与我的不同。然后我尝试将我的示例修改为更像 g5 并得到完全相同的错误消息:wandbox.org/permlink/VGuqQBUZMxyCiV4d 我认为我们可以关闭此案例。
【解决方案2】:

看起来像一个编译器错误。

但是,在头文件中使用 lambda 会带来 ODR 问题。所以我会避免它。

:

template<auto X>
struct always_return {
  template<class...Args>
  auto operator()(Args&&...)const{ return X; }
};

template<bool B>
void wut(std::function<bool()> f = always_return<false>{})
{

或在

template<class T>
struct always_return_t {
  T t;
  template<class...Args>
  auto operator()(Args&&...)const{ return t; }
};
template<class T>
always_return_t<typename std::decay<T>::type> always_return(T&&t) {
  return {std::forward<T>(t)};
}
template<bool B>
void wut(std::function<bool()> f = always_return(false)){

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-16
    • 1970-01-01
    • 2015-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多