Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我应该如何在这里使用SFINAE过载解析?_C++_Templates_Sfinae - Fatal编程技术网

C++ 我应该如何在这里使用SFINAE过载解析?

C++ 我应该如何在这里使用SFINAE过载解析?,c++,templates,sfinae,C++,Templates,Sfinae,我想任何使用SFINAE的行为都可能被认为是一种黑客行为,但在这里我尝试了很长时间,我能做到的最好的办法就是在其中一个重载中使用默认的void*参数: struct Dog { Dog() {} void makeNull() {} }; // If no .makeNull() function this is eliminated template <typename T> constexpr auto HasMakeNullFunction() -

我想任何使用SFINAE的行为都可能被认为是一种黑客行为,但在这里我尝试了很长时间,我能做到的最好的办法就是在其中一个重载中使用默认的void*参数:

struct Dog 
{
    Dog() {}
    void makeNull() {}
    
};

// If no .makeNull() function this is eliminated
template <typename T>
constexpr auto HasMakeNullFunction() -> decltype(std::declval<T>().makeNull(), bool())
{
    return true;
}
// And this one is called. But I could only manage to do it with a default void* p = nullptr
template <typename T>
constexpr bool HasMakeNullFunction(void* p = nullptr)
{
    return false;
}

int main()
{

    constexpr bool b = HasMakeNullFunction<Dog>(); // True
    constexpr bool b2 = HasMakeNullFunction<int>(); // False

}
你应该怎么做?这确实有效,但是使用SFINAE的典型方法是使用一个专门的版本,在替换失败时调用它,对吗?另外,我不喜欢使用默认的void*,因为我可能会看到代码被误用和隐式转换为void*

的可能性,因为当指定Dog作为模板参数时,对HasMakeNullFunction的调用是不明确的

您可以定义一个类型特征来完全分离这两个重载。e、 g

template <typename T, typename = void>
struct has_makeNull : std::false_type {};
template <typename T>
struct has_makeNull<T, decltype(std::declval<T>().makeNull(), void())> : std::true_type {};

template <typename T>
constexpr auto HasMakeNullFunction() -> std::enable_if_t<has_makeNull<T>::value, bool>
{
    return true;
}
template <typename T>
constexpr auto HasMakeNullFunction() -> std::enable_if_t<!has_makeNull<T>::value, bool>
{
    return false;
}
因为当指定Dog作为模板参数时,对HasMakeNullFunction的调用是不明确的

您可以定义一个类型特征来完全分离这两个重载。e、 g

template <typename T, typename = void>
struct has_makeNull : std::false_type {};
template <typename T>
struct has_makeNull<T, decltype(std::declval<T>().makeNull(), void())> : std::true_type {};

template <typename T>
constexpr auto HasMakeNullFunction() -> std::enable_if_t<has_makeNull<T>::value, bool>
{
    return true;
}
template <typename T>
constexpr auto HasMakeNullFunction() -> std::enable_if_t<!has_makeNull<T>::value, bool>
{
    return false;
}
以前,通常在以下情况下定义有条件地从std::true\u类型或std::false\u类型派生的结构:

包括 样板 结构HasMakeNullFunction:std::false_type{}; 样板 结构HasMakeNullFunction :std::true_type{}; 结构狗 { 狗{} void makeNull{} }; int main { constexpr bool b=HasMakeNullFunction::value;//true constexpr bool b2=HasMakeNullFunction::value;//false 静态资产b; 静态_断言!b2; } 但是,有了概念,就更容易了:

样板 概念HasMakeNullFunction=需要T v{ {v.makeNull}; }; 结构狗 { 狗{} void makeNull{} }; int main { constexpr bool b=HasMakeNullFunction;//true constexpr bool b2=HasMakeNullFunction;//false 静态资产b; 静态_断言!b2; } 以前,通常在以下情况下定义有条件地从std::true\u类型或std::false\u类型派生的结构:

包括 样板 结构HasMakeNullFunction:std::false_type{}; 样板 结构HasMakeNullFunction :std::true_type{}; 结构狗 { 狗{} void makeNull{} }; int main { constexpr bool b=HasMakeNullFunction::value;//true constexpr bool b2=HasMakeNullFunction::value;//false 静态资产b; 静态_断言!b2; } 但是,有了概念,就更容易了:

样板 概念HasMakeNullFunction=需要T v{ {v.makeNull}; }; 结构狗 { 狗{} void makeNull{} }; int main { constexpr bool b=HasMakeNullFunction;//true constexpr bool b2=HasMakeNullFunction;//false 静态资产b; 静态_断言!b2; }
你喜欢C++的C++版本17?或者,如果C++20有更好的解决方案,我也希望看到。我不想说这是的重复,但这个问题应该有足够的信息来实现HasMakeNullFunction。这确实有效,但实际上不应该。当使用Dog nothings调用它时,会停止nullptr版本的有效性,因此调用是@super。我对其工作原理的推理是,它更喜欢非默认参数版本。没有给出参数,所以第一个偏好应该是没有参数的函数。你喜欢C++的什么版本?目标PATRIKRBORTS C++ 17。或者,如果C++20有更好的解决方案,我也希望看到。我不想说这是的重复,但这个问题应该有足够的信息来实现HasMakeNullFunction。这确实有效,但实际上不应该。当使用Dog nothings调用它时,会停止nullptr版本的有效性,因此调用是@super。我对其工作原理的推理是,它更喜欢非默认参数版本。没有参数,因此第一个首选项应该是没有参数的函数。在这种情况下,HasMakeNullFunction与has是冗余的_makeNull@Justin你的意思是在没有has_makeNull的情况下重载HasMakeNullFunction?但是如何在第二个重载HasMakeNullFunction上放置没有makeNull的约束?对不起,我的意思是,用户可以只做has_makeNull:,而不是HasMakeNullFunction:value@Justin我懂了。我想OP想要控制SFINAE的重载解析,HasMakeNullFunction可以作为它的示例,在has_makeNull的帮助下。@Zebrafish我想这是VS的问题;尤其是和都说不:在本例中,HasMakeNullFunction与has是冗余的_makeNull@Justin你的意思是在没有has_makeNull的情况下重载HasMakeNullFunction?但是如何在第二个重载HasMakeNullFunction上放置没有makeNull的约束?对不起,我的意思是,用户可以只做has_makeNull:,而不是HasMakeNullFunction:value@Justin我懂了。我想OP想要控制SFINAE的重载解析,HasMakeNullFunction可以作为它的示例,在has_makeNull的帮助下。@Zebrafish我想这是VS的问题;尤其是和say no:struct HasMakeNullFunction应该类似于std::void_t@Justin这真的没关系。这只是惯例,但没必要让它起作用
hout std::void\t,您需要makeNull返回void。使用std::void\u t,您可以允许其他返回类型。@Justin很好,我已经编辑了我的答案。您不需要std::void\u t,您可以说:decltypewhatever,voidstruct HasMakeNullFunction应该类似于std::void_t@Justin这真的没关系。这只是约定,但没有必要让它工作。如果没有std::void\u t,您需要makeNull返回void。使用std::void\u t,您可以使用其他返回类型。@贾斯汀:很好,我已经编辑了我的答案。您不需要std::void\u t,您可以说:decltypewhatever,void