使用模板重载功能


34

我正在尝试使用模板定义函数,并且我希望类型名是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

@frogatto不,布尔型返回值没有任何类型。
bg

@Klaus我已要求学习替代方法。根据当前答案,我决定简单定义两个函数。
bg

Answers:


25

除了非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;
}

演示版

更新

根据@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<typename T, typename ...U> concept one_of = (std::is_same_v<T, U> || ...); template<one_of<int, MyEnum> T> bool isFunction(T const& aVariable) {
Richard Smith

1
@RichardSmith我也更新了我的答案。我发现这更具可重用性和可扩展性。谢谢
NutCracker

21

有两种方法可以实现此目的。所有这些都涉及使用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;
}

1
如果存在其他签名(例如,假想的isFunction(std::string_view)),则此方法不适用于过载解析。签名仍然是有效的匹配,但是实例化会导致错误。
LF

您可以声明无用的签名为已删除:bool isFunction(std :: string_view)= delete;
ixjxk

我说的是额外的过载。在那种情况下,该无效签名最终可能是精确匹配(例如,对于字符串文字),从而阻止了重载。
LF

0

我已经改善了https://stackoverflow.com/a/60271100/12894563答案。在这种情况下,“如果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
StoryTeller-Unslander Monica

非常感谢您的评论,我弄错了。固定,godbolt.org
z /
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.