简体   繁体   English

对现有 function 重载的通用 function 模板推导

[英]Generic function template deduction over existing function overloads

I'm writing an extensible library where it has become convenient to overload STL's to_string() for custom types.我正在编写一个可扩展的库,可以方便地为自定义类型重载 STL 的to_string() For that I've designed a generic overload template that throws an exception if not specialized:为此,我设计了一个通用的重载模板,如果不是专门的,它会引发异常:

namespace std {
// ...
template < typename T >
inline std::string to_string(const T& in, const std::string& separator = ",") {
    throw std::runtime_error("invalid call to " + std::string(__func__) + "(): missing template specialization for type " + typeid(T).name());
}

}  // namespace std

This is useful mainly because the description will provide a clear explanation on the issue and how to solve it, and avoids having to use polymorphism to implement derived implementations (the function is only marginally/optionally required for certain applications such as serialization, I/O, etc.).这很有用,主要是因为描述将清楚地解释该问题以及如何解决它,并避免必须使用多态性来实现派生实现(function 对于某些应用程序(例如序列化、I/O)仅是少量/可选地需要, ETC。)。

However, the issue with this approach is that the overload template will be deduced even with types where <string> already provides an overload for.但是,这种方法的问题在于,即使对于<string>已经为其提供重载的类型,也会推导出重载模板。

My question is if is there a way to force the non-template overload to be used only when there is no non-template definition available ?我的问题是,是否有办法强制仅在没有可用的非模板定义时才使用非模板重载

I recommend that you do not generate a runtime exception for something that should be a compilation failure.我建议您不要为应该是编译失败的事情生成运行时异常。

It could look like this:它可能看起来像这样:

#include <string>
#include <type_traits>

namespace extra {
template <class T>
std::string to_string(const T& in) {
    if constexpr (std::is_arithmetic_v<T>) {
        return std::to_string(in); 
    } else {
        // using !is_same_v<T,T> to make it dependant on T (and always `false`)
        static_assert(!std::is_same_v<T,T>, "T needs extra::to_string overload");
        return {}; // will never happen
    }
}
}  // namespace extra

... and then you don't need to check if it's an arithmetic type at the call site: ...然后您无需在调用站点检查它是否是算术类型:

template <class T>
void func(const T& arg) {
    std::cout << extra::to_string(arg);
}

Demo演示

I ended up declaring to_string on a different namespace, and made use of type traits to delegate basic types towards STL's std::to_string :我最终在不同的命名空间上声明了to_string ,并利用类型特征将基本类型委托给 STL 的std::to_string

namespace extra {

template < typename T >
struct invalid : std::false_type { /* ... */ };

template < typename T >
inline std::string to_string(const T& in) {
    // static_assert(invalid< iT >::value, "Invalid call to extra::to_string(): missing template specialization for required type!");   // never compiles
    throw std::runtime_error("Invalid call to extra::_to_string(): missing template specialization for required types[" + std::string(typeid(T).name()) + "]!");
}

}  // namespace extra


template < typename T >
void func(const T& arg) {
    // ...
    if constexpr (std::is_arithmetic< T >()) {
        std::cout << std::to_string(arg);
    } else {
        std::cout << extra::to_string(arg);
    }
    // ...
}

Although I am still trying to figure out how to proper write the static assertion in order to generate the error during compilation, at this stage this behaves how I needed it to.尽管我仍在试图弄清楚如何正确编写 static 断言以在编译期间生成错误,但在这个阶段,这符合我的需要。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM