Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/161.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typo3/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++_Language Lawyer_Sfinae - Fatal编程技术网

C++ 具有多层类型测定的SFINAE

C++ 具有多层类型测定的SFINAE,c++,language-lawyer,sfinae,C++,Language Lawyer,Sfinae,下面的代码专门介绍了f()的两个版本。第一个检测向量并返回迭代器。第二个接受所有其他类型并返回一个副本 这无法在VC 2010上编译,因为GetIter2中存在一个错误,即GetIter::type不存在。这仅在使用非向量解析对f()的调用时发生。如果我删除了一层类型间接寻址,使用GetIter而不是GetIter2(参见注释行)作为返回类型,那么一切正常 我想我想知道这是编译器错误还是正确的行为。如果这看起来很奇怪,那是因为它减少了我在使用boost::range_迭代器时遇到的问题,而我不能

下面的代码专门介绍了f()的两个版本。第一个检测向量并返回迭代器。第二个接受所有其他类型并返回一个副本

这无法在VC 2010上编译,因为GetIter2中存在一个错误,即GetIter::type不存在。这仅在使用非向量解析对f()的调用时发生。如果我删除了一层类型间接寻址,使用GetIter而不是GetIter2(参见注释行)作为返回类型,那么一切正常

我想我想知道这是编译器错误还是正确的行为。如果这看起来很奇怪,那是因为它减少了我在使用boost::range_迭代器时遇到的问题,而我不能删除GetIter2所代表的内容

#include <vector>
using namespace std;

template<typename T>
struct GetIter {
};

template<typename T>
struct GetIter<vector<T>> {
    typedef typename vector<T>::iterator type;
};

template<typename T>
struct GetIter2
{
    typedef typename GetIter<T>::type type;
};

template<typename T>
typename enable_if<is_same<T, vector<int>>::value, typename GetIter2<T>::type>::type
//typename enable_if<is_same<T, vector<int>>::value, typename GetIter<T>::type>::type
f(T & t) {
    return t.begin();
}

template<typename T>
typename enable_if<!is_same<T, vector<int>>::value, T>::type
f(T & t) {
    return t;
}

int main(int argc, char* argv[])
{
    vector<int> v(2);
    int i = 6;

    f(v);
    f(i);  // error C2039: 'type' : is not a member of 'GetIter<T>'

    return 0;
}
#包括
使用名称空间std;
模板
结构GetIter{
};
模板
结构GetIter{
typedef typename向量::迭代器类型;
};
模板
结构GetIter2
{
typedef typename GetIter::type type;
};
模板
typename启用_if::type
//typename启用_if::type
f(T&T){
返回t.begin();
}
模板
typename启用\u如果>::值,T>::类型
f(T&T){
返回t;
}
int main(int argc,char*argv[])
{
向量v(2);
int i=6;
f(v);
f(i);//错误C2039:'type':不是'GetIter'的成员
返回0;
}
编辑: 这是我试图解决的实际问题。使用迭代器作为第二个参数对copy()的第二次调用会在boost::mpl::eval_if_c对象上产生类似的错误

#include <vector>
using namespace std;

#include <boost/range.hpp>
#include <boost/tti/has_type.hpp>

BOOST_TTI_TRAIT_HAS_TYPE(has_iterator, iterator)

template<typename InCont, typename Out>
typename enable_if<has_iterator<Out>::value, typename boost::range_iterator<Out>::type>::type
copy(InCont const & in_cont, Out & out_cont)
{
    return std::copy(boost::begin(in_cont), boost::end(in_cont), boost::begin(out_cont));
}

template<typename InCont, typename Out>
typename enable_if<!has_iterator<Out>::value, Out>::type
copy(InCont const & in_cont, Out & out_iter)
{
    return std::copy(boost::begin(in_cont), boost::end(in_cont), out_iter);
}

int main(int argc, char* argv[])
{
    vector<int> v1;
    vector<int> v2;

    copy(v1, v2);
    copy(v1, v2.begin());  // error C2039: 'type' : is not a member of 'boost::mpl::eval_if_c<C,F1,F2>'

    return 0;
}
#包括
使用名称空间std;
#包括
#包括
BOOST\u TTI\u TRAIT\u具有类型(具有迭代器、迭代器)
模板
typename启用_if::type
复印件(InCont const&in_cont,Out&Out_cont)
{
返回std::copy(boost::begin(in_cont)、boost::end(in_cont)、boost::begin(out_cont));
}
模板
typename启用_if::value,Out>::type
复印件(输入和输入,输出和输出)
{
返回std::copy(boost::begin(in_cont)、boost::end(in_cont)、out_iter);
}
int main(int argc,char*argv[])
{
向量v1;
矢量v2;
拷贝(v1,v2);
copy(v1,v2.begin());//错误C2039:'type':不是'boost::mpl::eval_if_c'的成员
返回0;
}
编辑2: 最新版本的boost::range_迭代器修复了最初的问题。一旦我修补了,事情就变得容易了。下面是我所看到的,使用boost::has_range_iterator检查容器:

#include <vector>
using namespace std;

#include <boost/range.hpp>

template<typename InCont, typename Out>
typename boost::range_iterator<Out>::type
copy(InCont const & in_cont, Out & out_cont)
{
    return std::copy(boost::begin(in_cont), boost::end(in_cont), boost::begin(out_cont));
}

template<typename InCont, typename Out>
typename enable_if<!boost::has_range_iterator<Out>::value, Out>::type
copy(InCont const & in_cont, Out out_iter)
{
    return std::copy(boost::begin(in_cont), boost::end(in_cont), out_iter);
}

int main(int argc, char* argv[])
{
    vector<int> v1;
    vector<int> v2;

    copy(v1, v2);
    copy(v1, v2.begin());

    return 0;
}
#包括
使用名称空间std;
#包括
模板
typename boost::range\u迭代器::type
复印件(InCont const&in_cont,Out&Out_cont)
{
返回std::copy(boost::begin(in_cont)、boost::end(in_cont)、boost::begin(out_cont));
}
模板
typename启用_if::value,Out>::type
复印件(输入和输出)
{
返回std::copy(boost::begin(in_cont)、boost::end(in_cont)、out_iter);
}
int main(int argc,char*argv[])
{
向量v1;
矢量v2;
拷贝(v1,v2);
复制(v1,v2.begin());
返回0;
}

我认为非向量GetIter缺少类型函数。 模板 结构GetIter{ T型;
};

我仍在试图找到标准的相关部分来解释为什么这不起作用。我认为这与
GetIter2
的替换有关,它没有失败,但随后访问
GetIter2::type
,然后确定
GetIter::type
不存在。通过使
GetIter2
模板无法立即替换,您不会得到错误。您可以通过稍微更改其定义来实现这一点:

template<typename T, typename ST = typename GetIter<T>::type>
struct GetIter2
{
    typedef ST type;
};
模板
结构GetIter2
{
typedef-ST型;
};
我能够使用以下代码在不修改boost类型的情况下让您的真实示例正常工作:

template<typename InCont, typename Out, typename = typename enable_if<has_iterator<Out>::value>::type>
typename boost::range_iterator<Out>::type
copy(InCont const & in_cont, Out & out_cont)
{
    return std::copy(boost::begin(in_cont), boost::end(in_cont), boost::begin(out_cont));
}
模板
typename boost::range\u迭代器::type
复印件(InCont const&in_cont,Out&Out_cont)
{
返回std::copy(boost::begin(in_cont)、boost::end(in_cont)、boost::begin(out_cont));
}

为什么它不起作用

规则是,从[temp.Decrete]开始,强调:

只有函数类型及其模板参数类型的即时上下文中的无效类型和表达式才能导致推断失败

直接上下文是您在声明本身中看到的内容。当您尝试替换
T=int
时发生的故障不在
typename GetIter2::type
的直接上下文中-当尝试确定该类型实际上是什么并且看到
GetIter
没有
type
成员时,会发生故障。因为这不在直接上下文中,所以这不是演绎失败——这是一个硬错误

注意:即使这是一个扣除失败,它仍然只适用于
std::vector
,而不适用于任何向量

如何使其工作

实际上,这里根本不需要SFINAE。只需为向量设置一个重载,为所有内容设置另一个重载:

template <class T, class A>
auto f(std::vector<T,A>& t) {
    return t.begin();
}

template <class T>
T f(T& t) {
    return t;
}
模板
自动f(标准::向量和t){
返回t.begin();
}
模板
电讯局长(电讯及电讯){
返回t;
}

这是故意的。GetIter只在没有迭代器的情况下生成迭代器类型或缺少的类型,这样SFINAE就知道如何避免了。您的建议对于显示的代码是正确的,但实际上我正在区分具有子类型“iterator”的类型和其他所有类型,因此需要显示复杂程度。你的第一个答案似乎是可行的,这个答案解释了原因。人们能够理解这些东西给我留下了深刻的印象,非常感谢你的帮助。如果你好奇,我正在制作允许容器作为arg的算法版本。我使用SFINAE来区分容器和迭代器,例如copy(in_cont,out_cont)和copy(in_cont,out_iter)。我不知道该选择哪个答案,因为它们都很重要。@tukra如果你的问题不能准确反映你的需要,你希望我们如何帮助你?我猜不出。并非所有容器的cod都小于