【问题标题】:Overloading a function using templates使用模板重载函数
【发布时间】:2020-06-01 04:14:55
【问题描述】:

我正在尝试使用模板定义一个函数,并且我希望类型名是 int 或 anEnum(我已定义的特定枚举)。我尝试了以下方法,但失败了:

template <int | anEnum T> // or <int T, anEnum T> or <int, anEnum T>
bool isFunction(const T &aVariable){}

我想做的是使用模板,而不是定义两个重载函数。 我更喜欢按如下方式调用函数,而程序员不必考虑类型

isFunction(aVariable) // and not isFunction<int> (aVariable) nor isFunction<anEnum> (aVariable)

基本上,我希望将此函数模板化为 int 和 aNum 类型。我已经搜索过这个,但找不到答案。我可能会错过什么?谢谢,

【问题讨论】:

  • 如果恰好是单个枚举或int类型,为什么不简单地编写两个函数呢?为什么在这种情况下需要模板?
  • 其他类型呢?你想为其他类型返回false还是不想为其他类型实例化函数。
  • @frogatto 不,bool 返回值没有任何类型。
  • @Klaus 我已经要求学习替代方案。根据当前的答案,我决定简单地定义这两个函数。

标签: c++ templates overloading


【解决方案1】:

除了非 C++20 答案之外,如果您有机会使用 C++20 及其concepts 功能,我建议您使用以下实现:

#include <iostream>
#include <concepts>

enum class MyEnum {
    A,
    B,
    C
};

template <typename T>
concept IntegralOrEnum = std::same_as<MyEnum, T> || std::integral<T>;

template <IntegralOrEnum T>
bool isFunction(T const& aVariable) {
    return true;
}

int main() {
    isFunction(MyEnum::A);
    isFunction(3);
    isFunction("my_string"); // error
    return 0;
}

Demo

更新

根据@RichardSmith的评论,这里有一个更具扩展性和可重用性的方法:

template <typename T, typename ...U>
concept one_of = (std::is_same_v<T, U> || ...);

template <one_of<int, MyEnum> T>
bool isFunction(T const& aVariable) {
    return true;
}

【讨论】:

  • 对于要求类型为两种特定类型之一的特定情况,这样的方法可能会更好:template&lt;typename T, typename ...U&gt; concept one_of = (std::is_same_v&lt;T, U&gt; || ...);template&lt;one_of&lt;int, MyEnum&gt; T&gt; bool isFunction(T const&amp; aVariable) {
  • @RichardSmith 我也更新了我的答案。我发现这更可重用和可扩展。谢谢
【解决方案2】:

有几种方法可以做到这一点。所有都涉及使用type_traits 标头。例如,您可以在函数体中对有问题的类型进行静态断言。

或者,如果您需要在其他重载中考虑这个函数,可以使用 SFINAE 技术。

template<typename T>
auto isFunction(const T &aVariable) 
  -> std::enable_if_t<std::is_same<T, int>::value || std::is_same<T,anEnum>::value, bool> {
}

如果类型不匹配,这将在调用之前从重载集中删除函数。但是,如果您不需要这种行为,静态断言确实可以提供对程序员更友好的错误消息。

【讨论】:

    【解决方案3】:

    这个解决方案怎么样?如果类型 T 满足您的要求,将编译带有该函数的代码。否则静态断言失败。

    #include <type_traits>
    enum anEnum {
        //
    };
    
    template <typename T, bool defined = std::is_same<T, int>::value ||
                                         std::is_same<T, anEnum>::value>
    bool isFunction(const T& aVariable)
    {
        static_assert(defined, "Invalid specialization");
    
        bool result = false;
        // Put your code here
        return result;
    }
    

    【讨论】:

    • 如果存在其他签名(例如,假设的isFunction(std::string_view)),这不适用于重载解析。签名仍然是有效匹配,但实例化会导致错误。
    • 您可以将无用的签名声明为已删除:bool isFunction(std::string_view) = delete;
    • 我说的是额外的重载。在这种情况下,这个无效的签名最终可能是完全匹配的(例如,对于字符串文字),从而阻止了重载。
    【解决方案4】:

    我改进了https://stackoverflow.com/a/60271100/12894563 答案。 'If constexpr' 可以在这种情况下提供帮助:

    template <typename T>
    struct always_false : std::false_type {};
    
    template <typename T>
    bool isFunction(const T& aVariable)
    {
        if constexpr(std::is_same_v<T, int> || std::is_same_v<T, anEnum>)
        {
            std::cout << "int\n";
            // put your code here
            return true;
        }
        else
        {
            static_assert(always_false<T>::value, "You should declare non-template function or write if constexpr branch for your type");
            return false;
        }
    }
    
    bool isFunction(std::string_view)
    {
        std::cout << "std::string_view\n";
        return true;
    }
    
    int main()
    {
        isFunction(std::string_view("1L"));
        isFunction(1);
        //isFunction(1L); // will produce an error message from static_assert
    }
    

    isFunction(1L) 将失败,因为没有重载函数或 'if constexpr' 分支。

    更新: 修正错过

    template <typename T>
    struct always_false : std::false_type {};
    

    https://godbolt.org/z/eh4pVn

    【讨论】:

    • static_assert(false, ...) 是格式不正确的 NDR,甚至没有被使用。如果你幸运的话,你的编译器会马上告诉你,就像 Clang 一样,godbolt.org/z/m_Gk9n
    • 非常感谢您的评论,我犯了一个错误。已修复,godbolt.org/z/eh4pVn
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-04
    • 1970-01-01
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多