提问人:Harry Williams 提问时间:6/13/2023 最后编辑:Harry Williams 更新时间:6/13/2023 访问量:95
如何为具有特定方法名称的类型专门化模板化函数?
How do I specialize a templated function for types that have a particular method name?
问:
第三方库为我们提供了一个看起来像这样的函数(显然实际函数要复杂得多):
template<typename T>
std::string toString(const T& value) {
std::cout << "Called 'unspecialized' toString" << std::endl;
return std::to_string(value);
}
由于这是来自第三方库,因此我无法更改此函数签名。
我们的许多内部类型都有一个方法,例如:toString
struct Foo {
std::string toString() const {
return "Foo";
}
};
理想情况下,调用函数将遵循内部类型的方法(如果有)。我尝试使用 SFINAE 实现此目的:toString
toString
template<typename T, typename Enable = decltype(std::declval<T>().toString())>
std::string toString(const T& value) {
std::cout << "Called 'specialized' toString" << std::endl;
return value.toString();
}
但是,现在调用此类类型会导致编译错误:toString
int main() {
toString(5); // OK
toString(Foo{}); // compilation error: call of overloaded 'toString(Foo)' is ambiguous
}
如何在不更改 的非专用版本的情况下解决此错误?toString
编辑:对于某些背景,这是 Google Test 函数的问题,该函数从单元测试(doc)中打印出值。该函数旨在查找特定类型的重载。如果找到一个,它将使用该重载来打印类型。如果它没有找到一个,它会使用其默认(“非专用”)实现,它只会转储字节。PrintTo
有几个答案提供了需要更改函数默认实现的解决方案。这些答案可能对其他用户有所帮助,但对这种情况没有帮助。我将 Paul 基于概念的答案标记为已接受,因为它似乎是唯一一个不需要修改默认签名的答案,即使它需要 C++20。
我认为这个问题可能更准确地归类为 Google Test 的限制。 我在 GitHub 中发现了至少一个问题可以解决这个问题,但它仍然悬而未决。
答:
在 C++20 中,这很容易。只需将您的 SFINAE 内容替换为以下内容:
template <typename T>
concept HasToString = requires(T t) { t.toString(); };
template<typename T> requires HasToString <T>
std::string toString(const T& value){
std::cout << "Called 'specialized' toString" << std::endl;
return value.toString();
}
另请参阅评论中的@TedLyngmo(更好的)产品。
这是我对 C++17 解决方案的尝试。
把问题转过来,用它替换你的SFINAE的东西(从来都不是我最喜欢的东西之一),以便只为算术类型选择内置的(调整测试以适应)。 使它特别整洁:to_string
if constexpr
template<class T>
std::string toString (const T& value)
{
if constexpr (std::is_arithmetic_v <T>)
{
std::cout << "Called 'unspecialized' toString" << std::endl;
return std::to_string (value);
}
else
{
std::cout << "Called 'specialized' toString" << std::endl;
return value.toString ();
}
}
评论
std::string toString(HasToString auto const& value)
会更容易?
toString
toString
T
T::toString()
评论