gpt4 book ai didi

c++ - g++ 和 clang++ SFINAE 和 SFINAE 失败的不同行为

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:30:23 27 4
gpt4 key购买 nike

C++11 专家的几个问题。

我正在与 SFINAE 打交道,我遇到了一个奇怪的情况,其中 g++ (4.9.2) 和 clang++ (3.5.0) 的行为不同。

我准备了以下示例代码。很抱歉,我无法做到更简洁。

#include <string>
#include <iostream>
#include <typeinfo>
#include <type_traits>

template <typename X>
class foo
{
private:
template <typename R>
using enableIfIsInt
= typename std::enable_if<std::is_same<X, int>::value, R>::type;

public:
foo ()
{ }

template <typename R = void>
enableIfIsInt<R> bar ()
{ std::cout << "bar: is int\n"; }

void bar ()
{
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]{"
<< typeid(enableIfIsInt<void>).name() << "}\n";
}
};


int main ()
{
foo<long> fl;
foo<int> fi;

fl.bar();
fi.bar();

return 0;
}

我的想法是创建一个模板 foo<X>类(通过 SFINAE)可以根据 X 以一种或另一种方式定义方法模板参数。

程序在 g++ 4.9.2 下编译良好,但在 clang++ 3.5.0 下出现以下错误

test.cpp:13:36: error: no type named 'type' in
'std::__1::enable_if<false, void>'; 'enable_if' cannot be used to disable
this declaration
= typename std::enable_if<std::is_same<X, int>::value, R>::type;
^~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:26:23: note: in instantiation of template type
alias 'enableIfIsInt' requested here
<< typeid(enableIfIsInt<void>).name() << "}\n";
^
test.cpp:36:7: note: in instantiation of member function
'foo<long>::bar' requested here
fl.bar();
^
1 error generated.

我想 clang++ 是对的,但我对 C++11 专家的第一个问题是:谁是对的? g++ 还是 clang++?

关于g++产生的程序输出,如下

bar: isn't int; is [i]{v}

所以 g++ 似乎忽略了 fl.bar();说明。

现在有点变化:我修改了第二个版本foo<X>::bar()这样

  void bar ()
{ std::cout << "bar: isn't int; is [" << typeid(X).name() << "]\n"; }

删除 std::enable_if在函数内部可憎。现在 g++ 和 clang++ 都可以毫无问题地编译,并且对于程序的两个编译版本,输出都是

bar: isn't int; is [l]
bar: isn't int; is [i]

那么,我的第二个问题是:我做错了什么?为什么,在 int情况下,我没有获得 "is int" foo<X>::bar() 的版本?

如果我在做一些傻事,请耐心等待:我正在努力学习 C++11。

抱歉我的英语不好。

最佳答案

clang 的错误不是来自替换失败。它来自这里:

  void bar ()
{
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]{"
<< typeid(enableIfIsInt<void>).name() << "}\n"; // <==
}

enableIfIsInt<void>不在当前上下文中,这是 X 的严重失败不是 int .您根本不能在该上下文中使用该表达式。

一旦你删除它 - 非模板 bar()总是被调用。这是因为这两个函数是等价匹配,并且在重载决策中非模板优先于模板。

所以真正的解决方案是使用标签分发:

void bar() { bar(std::is_same<X, int>{}); }

void bar(std::true_type ) {
std::cout << "bar: is int\n";
}

void bar(std::false_type ) {
std::cout << "bar: isn't int; is [" << typeid(X).name() << "]\n";
}

两个编译器都愉快地产生了:

bar: isn't int; is [l]
bar: is int

关于c++ - g++ 和 clang++ SFINAE 和 SFINAE 失败的不同行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36578055/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com