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

C++ SFINAE以返回类型工作,但不作为模板参数

C++ SFINAE以返回类型工作,但不作为模板参数,c++,templates,c++11,sfinae,C++,Templates,C++11,Sfinae,我已经多次使用SFINAE习惯用法,并且习惯于将我的std::enable_if放在模板参数中,而不是放在返回类型中。然而,我遇到了一些不起效的小事,我不知道为什么。首先,以下是我的主要观点: int main() { foo(5); foo(3.4); } 下面是触发错误的foo的实现: template<typename T, typename = typename std::enable_if<std::is_integral<T>

我已经多次使用SFINAE习惯用法,并且习惯于将我的
std::enable_if
放在模板参数中,而不是放在返回类型中。然而,我遇到了一些不起效的小事,我不知道为什么。首先,以下是我的主要观点:

int main()
{
    foo(5);
    foo(3.4);
}
下面是触发错误的
foo
的实现:

template<typename T,
         typename = typename std::enable_if<std::is_integral<T>::value>::type>
auto foo(T)
    -> void
{
    std::cout << "I'm an integer!\n";
}

template<typename T,
         typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
auto foo(T)
    -> void
{
    std::cout << "I'm a floating point number!\n";
}
编辑


和。

您应该看看
14.5.6.1函数模板重载(C++11标准),其中定义了函数模板等效性。简言之,默认模板参数不被考虑,因此在第一种情况下,相同的函数模板定义了两次。在第二种情况下,返回类型中使用了引用模板参数的表达式(再次参见14.5.6.1/4)。由于此表达式是签名的一部分,因此您会得到两个不同的函数模板声明,因此SFINAE有机会工作。

您应该看看定义函数模板等效性的
14.5.6.1函数模板重载(C++11标准)。简言之,默认模板参数不被考虑,因此在第一种情况下,相同的函数模板定义了两次。在第二种情况下,返回类型中使用了引用模板参数的表达式(再次参见14.5.6.1/4)。由于此表达式是签名的一部分,因此您会得到两个不同的函数模板声明,因此SFINAE有机会工作。

模板的
=…
只提供了一个默认参数。这不是实际签名的一部分,看起来像

template<typename T, typename>
auto foo(T a);
模板
自动foo(ta);
对于这两种功能

根据您的需要,此问题最通用的解决方案是使用标记分派

struct integral_tag { typedef integral_tag category; };
struct floating_tag { typedef floating_tag category; };

template <typename T> struct foo_tag
: std::conditional<std::is_integral<T>::value, integral_tag,
                    typename std::conditional<std::is_floating_point<T>::value, floating_tag,
                                               std::false_type>::type>::type {};

template<typename T>
T foo_impl(T a, integral_tag) { return a; }

template<typename T>
T foo_impl(T a, floating_tag) { return a; }

template <typename T>
T foo(T a)
{
  static_assert(!std::is_base_of<std::false_type, foo_tag<T> >::value,
                 "T must be either floating point or integral");
  return foo_impl(a, typename foo_tag<T>::category{});
}

struct bigint {};
template<> struct foo_tag<bigint> : integral_tag {};

int main()
{
  //foo("x"); // produces a nice error message
  foo(1);
  foo(1.5);
  foo(bigint{});
}
struct integral_标记{typedef integral_标记类别;};
结构浮动标记{typedef浮动标记类别;};
模板结构foo_标记
:std::conditional::type{};
模板
T foo_impl(ta,integral_tag){return a;}
模板
T foo_impl(ta,floating_标记){返回a;}
模板
T-foo(T-a)
{
static_assert(!std::is_base_of::value,
“T必须是浮点或整数”);
返回foo_impl(a,typename foo_tag::category{});
}
结构bigint{};
模板结构foo_标记:integral_标记{};
int main()
{
//foo(“x”);//生成一条很好的错误消息
傅(1),;
foo(1.5);
foo(bigint{});
}

模板的
=…
只提供了一个默认参数。这不是实际签名的一部分,看起来像

template<typename T, typename>
auto foo(T a);
模板
自动foo(ta);
对于这两种功能

根据您的需要,此问题最通用的解决方案是使用标记分派

struct integral_tag { typedef integral_tag category; };
struct floating_tag { typedef floating_tag category; };

template <typename T> struct foo_tag
: std::conditional<std::is_integral<T>::value, integral_tag,
                    typename std::conditional<std::is_floating_point<T>::value, floating_tag,
                                               std::false_type>::type>::type {};

template<typename T>
T foo_impl(T a, integral_tag) { return a; }

template<typename T>
T foo_impl(T a, floating_tag) { return a; }

template <typename T>
T foo(T a)
{
  static_assert(!std::is_base_of<std::false_type, foo_tag<T> >::value,
                 "T must be either floating point or integral");
  return foo_impl(a, typename foo_tag<T>::category{});
}

struct bigint {};
template<> struct foo_tag<bigint> : integral_tag {};

int main()
{
  //foo("x"); // produces a nice error message
  foo(1);
  foo(1.5);
  foo(bigint{});
}
struct integral_标记{typedef integral_标记类别;};
结构浮动标记{typedef浮动标记类别;};
模板结构foo_标记
:std::conditional::type{};
模板
T foo_impl(ta,integral_tag){return a;}
模板
T foo_impl(ta,floating_标记){返回a;}
模板
T-foo(T-a)
{
static_assert(!std::is_base_of::value,
“T必须是浮点或整数”);
返回foo_impl(a,typename foo_tag::category{});
}
结构bigint{};
模板结构foo_标记:integral_标记{};
int main()
{
//foo(“x”);//生成一条很好的错误消息
傅(1),;
foo(1.5);
foo(bigint{});
}

模板中的值起作用:

template<typename T,
         typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
auto foo(T)
    -> void
{
    std::cout << "I'm an integer!\n";
}

template<typename T,
         typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
auto foo(T)
    -> void
{
    std::cout << "I'm a floating point number!\n";
}
模板
自动foo(T)
->空虚
{
std::cout void
{

模板工作中的std::cout值:

template<typename T,
         typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
auto foo(T)
    -> void
{
    std::cout << "I'm an integer!\n";
}

template<typename T,
         typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
auto foo(T)
    -> void
{
    std::cout << "I'm a floating point number!\n";
}
模板
自动foo(T)
->空虚
{
std::cout void
{

std::cout Ok。实际演示:和。附加信息:与VS 2012 11月CTP相同。Ok。实际演示:和。附加信息:与VS 2012 11月CTP相同。非常感谢。这个解释至少简单明了。我不知道这个规则:)我喜欢这句话:“不考虑默认模板参数”@cpp初学者好吧,我想这或多或少是因为在等价性定义中没有对默认参数的引用。所有这些都来自C++11标准,而不是某种“参考”网站。如果你对C++14感兴趣,我相信至少最好看看最终草案(也是免费的),而不是提案遗漏了许多相关部分。非常感谢。这一解释至少简单明了。我不知道这条规则:)我喜欢这句话:“不考虑默认模板参数”@cpp初学者好吧,我想这或多或少是因为在等价性定义中没有对默认参数的引用。所有这些都来自C++11标准,而不是某种“参考”网站。如果你对C++14感兴趣,我相信至少最好看看最终草案(也是免费的),而不是缺少许多相关部分。这不是非常通用-它特定于此确切情况-整数与浮点。这不是非常通用-它特定于此确切情况-整数与浮点。额外:
typename=typename…
表示默认参数,只能显示一次。而如果替换为
typename
,它的意思是。额外:
typename=typename…
表示默认参数,只能出现一次。而如果替换为
typename…
,它的意思是。