Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.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++ C++;_C++_Sfinae - Fatal编程技术网

C++ C++;

C++ C++;,c++,sfinae,C++,Sfinae,我在一个项目中大量使用函数SFINAE,不确定以下两种方法(风格除外)之间是否有任何差异: 我看到方法2在stackoverflow中使用得更频繁,但我更喜欢方法1 这两种方法有什么不同的情况吗 我看到方法2在stackoverflow中使用得更频繁,但我更喜欢方法1 建议:首选方法2 这两种方法都适用于单个函数。当您有多个具有相同签名的函数,并且希望只启用集合中的一个函数时,就会出现问题 假设您希望在bar()时启用foo(),版本1(假设它是constexpr函数)为true,在bar()为

我在一个项目中大量使用函数SFINAE,不确定以下两种方法(风格除外)之间是否有任何差异:

我看到方法2在stackoverflow中使用得更频繁,但我更喜欢方法1

这两种方法有什么不同的情况吗

我看到方法2在stackoverflow中使用得更频繁,但我更喜欢方法1

建议:首选方法2

这两种方法都适用于单个函数。当您有多个具有相同签名的函数,并且希望只启用集合中的一个函数时,就会出现问题

假设您希望在
bar()
时启用
foo()
,版本1(假设它是
constexpr
函数)为
true
,在
bar()
false
时启用
foo()
,版本2

因为SFINAE修改了函数的签名,所以它是有效的

不相关的观察:还有第三种方法:启用/禁用返回类型(显然,类/结构构造函数除外)

模板
std::enable_if_t foo()//版本1
{ }
模板
std::enable_if_t foo()//版本2
{ }
与方法2一样,方法3与选择具有相同签名的替代函数兼容。

此外,选择方法2的另一个原因是,使用方法1,您可以(意外地)传递一个显式类型参数作为第二个模板参数,并完全破坏SFINAE机制。这可能是打字错误、复制/粘贴错误,或者是在较大的模板机制中出现疏忽

#include <cstdlib>
#include <type_traits>
#include <iostream>

// NOTE: foo should only accept T=int
template <class T, class = std::enable_if_t<std::is_same_v<T, int>>>
void foo(){
    std::cout << "method 1" << std::endl;
}

int main(){

    // works fine
    foo<int>();

    // ERROR: subsitution failure, as expected
    // foo<double>();

    // Oops! also works, even though T != int :(
    foo<double, double>();

    return 0;
}
#包括
#包括
#包括
//注意:foo应该只接受T=int
模板
void foo(){

std::cout你如何运行这个程序?@alter igel它需要一个C++17编译器。我使用MSVC 2019测试这个例子,但我主要使用Clang。相关:C++20也引入了新的概念方法:-)@Jarod42概念是我从C++20最需要的东西之一。感谢您的精彩解释,从现在起我将更喜欢方法2和3:-)“默认模板参数不会更改签名”-这与您的第二个变量有什么不同,它也使用默认模板参数?@Eric-说起来不简单…我想另一个答案可以更好地解释这一点…如果SFINAE启用/禁用默认模板参数,
foo()
函数在使用显式的第二个模板参数调用时保持可用(
foo();
调用)。如果仍然可用,则与另一个版本存在歧义。对于方法2,SFINAE启用/禁用第二个参数,而不是默认参数。因此,您不能调用它来解释参数,因为存在不允许第二个参数的替换失败。因此版本不可用,因此没有歧义方法3具有通常不会泄漏到符号名中的附加优势。变量
auto foo()->std::enable_if_t
通常有助于避免隐藏函数签名并允许使用函数参数。@max66:所以关键点是,如果提供了参数且不需要默认值,则模板参数默认值中的替换失败不是错误?
method 1
method 2
Done...
template <typename T, typename = std::enable_if_t<true == bar<T>()>>
void foo () // version 1
 { }

template <typename T, typename = std::enable_if_t<false == bar<T>()>>
void foo () // version 2
 { }
template <typename T, std::enable_if_t<true == bar<T>(), bool> = true>
void foo () // version 1
 { }

template <typename T, std::enable_if_t<false == bar<T>(), bool> = true>
void foo () // version 2
 { }
template <typename T>
std::enable_if_t<true == bar<T>()> foo () // version 1
 { }

template <typename T>
std::enable_if_t<false == bar<T>()> foo () // version 2
 { }
#include <cstdlib>
#include <type_traits>
#include <iostream>

// NOTE: foo should only accept T=int
template <class T, class = std::enable_if_t<std::is_same_v<T, int>>>
void foo(){
    std::cout << "method 1" << std::endl;
}

int main(){

    // works fine
    foo<int>();

    // ERROR: subsitution failure, as expected
    // foo<double>();

    // Oops! also works, even though T != int :(
    foo<double, double>();

    return 0;
}