模板函数覆盖

template function override

提问人:sameer karjatkar 提问时间:8/10/2023 最后编辑:sameer karjatkar 更新时间:8/11/2023 访问量:90

问:

我正在尝试为基于类型的函数创建一个模板 speacialization

因此,例如,对于我有的类型编号

template <class ElementType, typename = typename TEnableIf<TNot<TIsSame<ElementType, double>>::Value>::Type>
void WriteExtras(IGLTFJsonWriter &Writer, const FString &Key, const TSharedPtr<FJsonValue> &Value) const
{
    Writer.Write(Key, float(Value->AsNumber()));
    // Perform further processing or write logic for double
}

现在我想再有一个定义,但对于布尔......但如果我尝试这样做

template <class ElementType, typename = typename TEnableIf<TNot<TIsSame<ElementType, bool>>::Value>::Type>
void WriteExtras(IGLTFJsonWriter &Writer, const FString &Key, const TSharedPtr<FJsonValue> &Value) const
{
    Writer.Write(Key, Value->AsBool());
    // Perform further processing or write logic for double
}

我收到错误Function already defined

我将函数模板称为

WriteExtras< EJson>(Writer,Key, Pair.Value);

EJson 是一个枚举

enum class EJson
{
    None,
    Null,
    String,
    Number,
    Boolean,
    Array,
    Object
};

经过@Jan建议,以下是我的模板实现

template <bool 条件,typename T = void> 使用 EnableIf_t = typename TEnableIf<Condition, T>::type;

template <class ElementType>
auto WriteCustom(IGLTFJsonWriter& Writer, const FString& Key, const TSharedPtr<FJsonValue>& Value) const
    ->EnableIf_t<TNot<TIsSame<ElementType, FString>>::Value>
    //->TEnableIf<TIsSame<ElementType, FString>::Value>
{
    Writer.Write(Key, Value->AsString());
    const FText Title = FText::FromString(TEXT("Template"));
    FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(TEXT("FString")), &Title);
}


template <class ElementType>
auto WriteCustom(IGLTFJsonWriter& Writer, const FString& Key, const TSharedPtr<FJsonValue>& Value) const
    ->EnableIf_t<TNot<TIsSame<ElementType, bool>>::Value>
    //->TEnableIf<TIsSame<ElementType, FString>::Value>
{
    Writer.Write(Key, Value->AsBool());
    const FText Title = FText::FromString(TEXT("Template"));
    FMessageDialog::Open(EAppMsgType::Ok, FText::FromString(TEXT("Bool")), &Title);
}

当我尝试打电话时

WriteCustom<EJson>(Writer,Key, Pair.Value);

它给出错误

C++ variadic-templates 模板专用化

评论

1赞 molbdnilo 8/10/2023
看起来第一个对除此以外的所有内容都启用,第二个对 - 之外的所有内容都启用了,并且每个类型要么是“不是”,要么是“不是”。 两者都不是,因此两个模板都会实例化。doublebooldoubleboolEJson
0赞 Phil1970 8/10/2023
一种可能的替代方法是,您的自由函数具有单个模板参数,然后调用具有额外参数(每种可能性具有不同类型)或模板类专用化的函数。
0赞 molbdnilo 8/10/2023
我希望将用途视为 or 或(使用非类型参数)。该类型不提供任何有用的信息。WriteExtras<float>(Writer,Key, Pair.Value);WriteExtras<EJson::Number>(Writer,Key, Pair.Value);EJson
0赞 sameer karjatkar 8/10/2023
@molbdnilo这是我想避免的,指定类型......我希望模板从我的 FJsonValue 中推断出类型
0赞 molbdnilo 8/10/2023
@sameerkarjatkar我对此有预感。它不能那样做;模板在编译时实例化和选择,不能依赖于运行时值。

答:

2赞 Jan Schultke 8/10/2023 #1

这两个函数实际上声明了相同的函数:

template <class ElementType,
          class = typename TEnableIf<TNot<TIsSame<ElementType, double>>::Value>::Type>
void WriteExtras(/* same as below */) const;

template <class ElementType,
          class = typename TEnableIf<TNot<TIsSame<ElementType, bool>>::Value>::Type>
void WriteExtras(/* same as above */) const;

它们之间的唯一区别是模板参数的默认参数,但这并不能使其中一个参数成为单独的实体。这就像写:

int foo(int x = 0); 
int foo(int x = 1);

正确执行 SFINAEenable_if

您需要在函数签名中的其他位置(例如参数、noexcept 规范、返回类型等)执行 SFINAE(或您的自定义模仿)。对于函数,最好的方法之一是使用返回类型,因为它不会更改模板参数列表:std::enable_if

// convenience alias (since C++14)
// similar to std::enable_if_t
template <bool Condition, typename T = void>
using EnableIf_t = typename EnableIf<Condition, T>::type;

// note: you could also make a convenience variable template for TIsSame

template <class ElementType>
auto WriteExtras(/* ... */) const
  -> TEnableIf_t<not TIsSame<ElementType, double>::Value>;
// note: TNot is unnecessary, you can just write '!' or 'not' here

template <class ElementType>
auto WriteExtras(/* ... */) const
  -> TEnableIf_t<not TIsSame<ElementType, bool>::Value>;

或者,有些人更喜欢在另一个非类型模板参数 (NTTP) 中执行 SFINAE 部分:

template <class ElementType, TEnableIf_t<not TIsSame<ElementType, double>::Value, int> = 0>
void WriteExtras(/* ... */) const;

这样做的原因是,该 NTTP 的函数类型不同,因此函数实际上并不相同。也无法通过显式提供模板参数来绕过约束。

替代解决方案

但是,您是否应该在这里使用 SFINAE 也是非常值得怀疑的。您可以使用 (C++17) 实现相同的目的:if constexpr

template <class ElementType>
void WriteExtras(/* ... */) const {
    if constexpr (TIsSame<ElementType, double>::value) {
        // ...
    }
    else if constexpr (TIsSame<ElementType, bool>::value) {
        // ...
    }
    else {
        // TODO: handle this error case somehow
        //       (specifics may depend on language version and compiler)
    }
}

您还可以使用完全专用化,只要只有一个模板参数:

template <class ElementType> // Inside class
// Primary template is defined as deleted, so only calling
// the specializations is allowed.
void WriteExtras(/* ... */) const = delete;

template <> // Outside class
void JsonWriter::WriteExtras<double>(/* ... */) const { /* ... */ }

// More specializations here ...

评论

0赞 sameer karjatkar 8/10/2023
我不能在模板中添加或条件<class ElementType, typename = typename TEnableIf<TNot<TIsSame<ElementType, double> ||bool >::Value>::Type> void WriteExtras(IGLTFJsonWriter& Writer, const FString& Key, const TSharedPtr<FJsonValue>& Value) const ?
0赞 Jan Schultke 8/10/2023
@sameerkarjatkar在一定程度上可以,但不能使用类型参数的默认参数。我已经扩展了答案。
0赞 sameer karjatkar 8/10/2023
它需要 C++ 20 吗?我在 Vs 2022 上遇到错误,类型为“TEnableIf<TNot<TIsSame<T,double>>::Value,int>”的非类型模板参数至少需要“/std:c++20”
0赞 Jan Schultke 8/10/2023
@sameerkarjatkar再看一遍,它只是 ,这使得 template 参数有效地成为 ,因为它使用了便利别名。TEnableIf_tint
1赞 Jan Schultke 8/10/2023
你能在编译器资源管理器或其他东西上重现错误吗?