5

源代码(在问题的末尾)会引发我认为是 Solaris Studio(而不是其他编译器)上的错误。

为清楚起见,错误消息已用新行重新格式化:

"overload.cpp", line 44: Error:
runGenEntries<std::vector<int>>(const GenEntryRuleDriven<int>&, const std::vector<int>&)
and
runGenEntries<std::vector<int>>(const GenEntryRulesDriven<int>&, const std::vector<int>&)
have same extern name
"__1cNrunGenEntries4nDstdGvector4Cin0AJallocator4Ci_____6FrkTArk1_v_".
1 Error(s) detected.

注意两个函数 runGenEntries 的第一个参数仅相差一个字符(规则末尾的“s”)

当第一个参数的类型为:

const typename GenEntryRulesDrivenType<typename InputsType::value_type>::type

当第一个参数不是类型时不会发生:

const typename GenEntryRulesDriven<typename InputsType::value_type>

最终解析为相同的类型!

这是仅在 Solaris 上实现的一些晦涩的 C++ 规则的结果吗?还是当它破坏符号时这是一个 Solaris Studio 错误?

完整的源码

以下源代码可以在任何编译器上进行编译。

定义将激活引发错误的代码,或者激活应该产生相同结果的代码(但这次,没有错误):

#include <iostream>
#include <vector>

template<typename T>
struct GenEntryRulesDriven
{
   void foo() const
   {
   }
};

template<typename T>
struct GenEntryRuleDriven
{
   void bar() const
   {
   }
   std::string toto; // to have a different size than GenEntryRulesDriven
};


template <typename T>
struct GenEntryRulesDrivenType
{
   typedef GenEntryRulesDriven<T> type;
};

template <typename T>
struct GenEntryRuleDrivenType
{
   typedef GenEntryRuleDriven<T> type;
};

#if 1 // Gives an error

template <typename InputsType>
void runGenEntries(const typename GenEntryRulesDrivenType<
                          typename InputsType::value_type>::type &genEntry,
                          const InputsType& inputs)
{
   genEntry.foo();
}

template <typename InputsType>
void runGenEntries(const typename GenEntryRuleDrivenType<
                          typename InputsType::value_type>::type &genEntry,
                          const InputsType& inputs)
{
   genEntry.bar();
}

#else // No error but same types as above!

template <typename InputsType>
void runGenEntries(const typename GenEntryRulesDriven<
                          typename InputsType::value_type> &genEntry,
                          const InputsType& inputs)
{
   genEntry.foo();
}

template <typename InputsType>
void runGenEntries(const typename GenEntryRuleDriven<
                          typename InputsType::value_type> &genEntry,
                          const InputsType& inputs)
{
   genEntry.bar();
}

#endif

int
main()
{
   std::vector<int> v;
   GenEntryRulesDriven<int> rulesDriven;
   runGenEntries(rulesDriven, v);

   GenEntryRuleDriven<int> ruleDriven;
   runGenEntries(ruleDriven, v);

   return 0;
}

此代码是在以下平台上编译的:

bash$ uname -a
SunOS pegasus 5.10 Generic_118855-33 i86pc i386 i86pc
bash$ CC -V
CC: Sun C++ 5.10 SunOS_i386 128229-07 2010/03/24
4

1 回答 1

3

简短的回答

简短的回答:这似乎是“无法修复”的错误 6532605(我看到它在众多谷歌搜索中被引用,但我无法在https://support.oracle.com/rs?type=bug&id=6532605上打开错误本身)。

Qt 开发人员所做的解决方法是将方法定义放在单独的编译单元(.cpp 文件)中。

背景

如果您对 CC 抱怨的符号名称进行 demangle,您可以看到它正在编译一个 const __type_0& 参数作为第一个参数:

$ echo __1cNrunGenEntries4nDstdGvector4Cin0AJallocator4Ci_____6FrkTArk1_v_ | c++filt
void runGenEntries<std::vector<int> >(const __type_0&,const __type_0&)
$

在完全相同的 Solaris 10 机器上使用 g++ 3.4.6,块 1 中的符号将分解为:

runGenEntries<std, vector<int, std::allocator,<int>void> >(const GenEntryRuleDrivenType<int::value_type>::type(const GenEntryRuleDrivenType<int::value_type>&)&)
runGenEntries<std, vector<int, std::allocator,<int>void> >(const GenEntryRulesDrivenType<int::value_type>::type(const GenEntryRulesDrivenType<int::value_type>&)&)

为什么甲骨文无法实​​现同样的目标,这超出了我的理解。

Qt 解决方法

引用此错误/解决方法的 Qt 代码在此处

我们可以看到有两个用相似名称声明的函数:

Expression::Ptr DocFN::typeCheck(const StaticContext::Ptr &context, const SequenceType::Ptr &reqType);
Expression::Ptr IdFN::typeCheck(const StaticContext::Ptr &context, const SequenceType::Ptr &reqType);

并且每个都在其自己的源代码(此处此处)中编译以解决该错误。

不支持的解决方案:更改 ccfe 中的 mangling 选项

这里,您还可以使用-Qoption ccfe -abiopt=mangle6. 使用这些标志,代码编译成功,符号(解构)是:

void runGenEntries<std::vector<int> >(const GenEntryRuleDrivenType<__type_0::value_type>::type&,const __type_0&)
void runGenEntries<std::vector<int> >(const GenEntryRulesDrivenType<__type_0::value_type>::type&,const __type_0&)

问题是这个编译选项不受支持,正如 Steve Clamage 所写:

最后,编译器有一个隐藏选项可以无条件地修复所有已知的错误。我们不公开该选项,因为

  • 它是不稳定的。如果发现更多错误,未来的补丁或版本可能会改变修改。
  • 您可能需要使用此选项重新编译所有 C++ 代码,包括第 3 方库。
  • 如果您使用此选项创建库,它可能与不使用该选项编译的代码不兼容。
  • 与所有隐藏选项一样,如有更改或删除,恕不另行通知。
  • 我们将此选项视为“使用风险自负”。

如果在所有这些警告之后您仍然想尝试该选项,那么它是:

-Qoption ccfe -abiopt=mangle6

确保将它添加到每个 CC 命令中,然后重新编译所有内容。

幸运的是,Solaris 或 Studio 附带的 C++ 系统库都不受此错误或隐藏选项的影响,因此您无需担心这些库的不同版本。

于 2014-06-19T14:12:20.647 回答