你好
我使用模板在C ++中编写代码,并尝试实现SFINAE,当不支持运算符+
时会触发该错误。
我写下面的代码
#include <iostream>
#include <type_traits>
class B
{
};
template<typename T1,typename T2>
struct IsSameT :std::false_type
{
//static constexpr bool value = false;
};
template<typename T>
struct IsSameT<T,T> :std::true_type
{
//static constexpr bool value = true;
};
template<typename T1, typename T2>
struct HasPlusT
{
private:
using T1_t = typename std::remove_reference<T1>::type;
using T2_t = typename std::remove_reference<T2>::type;
template<typename U1, typename = decltype(T1_t() + T2_t())>
static char test(void *);
template<typename>
static long test(...);
public:
static constexpr bool value = IsSameT<decltype(test<T1,T2>(nullptr)),char>::value;
};
template<typename T1,typename T2, bool = HasPlusT<T1,T2>::value>
struct PlusResultT
{
using T1_t = typename std::remove_reference<T1>::type;
using T2_t = typename std::remove_reference<T2>::type;
using Type = decltype(T1_t() + T2_t());
};
template<typename T1,typename T2>
struct PlusResultT<T1,T2,false>
{
using T1_t = typename std::remove_reference<T1>::type;
using T2_t = typename std::remove_reference<T2>::type;
using Type = decltype(T1_t() + T2_t());
};
int main()
{
constexpr bool value = HasPlusT<B,B>::value;
return 0;
}
我希望
constexpr bool value = HasPlusT<B,B>::value
返回false
,但是会生成错误实施中有什么问题?
B类没有运算符+,我希望constexpr bool value => HasPlusT :: value返回true。但是会生成编译错误
与'operator +'不匹配(操作数类型为'HasPlusT :: T1_t {aka B}'和>'HasPlusT :: T2_t {aka B}'))Demo.cpp / Demo C / C ++>问题
=============================================
支持类模板的新实现。为什么以下实现无法验证运算符+存在
#include <iostream>
#include <type_traits>
#include <array>
#include <vector>
#include <utility>
template<typename T1,typename T2>
struct IsSameT :std::false_type
{
//static constexpr bool value = false;
};
template<typename T>
struct IsSameT<T,T> :std::true_type
{
//static constexpr bool value = true;
};
template<typename T, typename U>
struct IsFuntamentalHelper : IsSameT<T,U>
{
//static constexpr bool value = IsSameT<T,U>::value;
};
template<typename T>
struct IsFundamentalT : std::false_type
{
//static constexpr boo value = std::false_type;
};
template<>
struct IsFundamentalT<int> : IsFuntamentalHelper<int,int>
{
};
template<>
struct IsFundamentalT<float> : IsFuntamentalHelper<float,float>
{
};
template<>
struct IsFundamentalT<double> : IsFuntamentalHelper<double,double>
{
};
template<>
struct IsFundamentalT<long>: IsFuntamentalHelper<long,long>
{
};
template<typename T>
using enable_if_t = typename std::enable_if<IsFundamentalT<T>::value, T>::type;
template<typename T>
class A
{
public:
template<typename = enable_if_t<T>>
operator T()
{
return t ;
}
A<T>():t()
{
}
template<typename = enable_if_t<T>>
A<T>(T a)
{
std::cout << "integer" << std::endl;
this->t = a;
}
A<T>(A<T> const & a)
{
this->t = a.t;
}
public:
A<T> add(A<T> & a)
{
t += a.t;
return *this;
}
friend A<T> operator + (A<T> & a1, A<T> & a2)
{
return a1.add(a2);
}
T t;
};
template<typename T1, typename T2>
struct HasPlusT
{
private:
template <typename T>
using Rr = typename std::remove_reference<T>::type;
template<typename U1, typename U2>
static auto test(void *)
-> decltype(std::declval<Rr<U1>>() + std::declval<Rr<U2>>() , '0');
template<typename...>
static long test(...);
public:
static constexpr bool value
= IsSameT<decltype(test<T1,T2>(nullptr)),char>::value;
};
template<typename T1,typename T2, bool = HasPlusT<T1,T2>::value>
struct PlusResultT
{
using T1_t = typename std::remove_reference<T1>::type;
using T2_t = typename std::remove_reference<T2>::type;
using Type = decltype(T1_t() + T2_t());
};
template<typename T1,typename T2>
struct PlusResultT<T1,T2,false>
{
using T1_t = typename std::remove_reference<T1>::type;
using T2_t = typename std::remove_reference<T2>::type;
using Type = decltype(T1_t() + T2_t());
};
int main()
{
constexpr bool value = HasPlusT<A<int>,A<int>>::value;
std::cout << value << std::endl;
return 0;
}
最佳答案
试试看
template <typename T1, typename T2>
struct HasPlusT
{
private:
template <typename T>
using Rr = typename std::remove_reference<T>::type;
template<typename U1, typename U2>
static auto test(void *)
-> decltype(std::declval<Rr<U1>>() + std::declval<Rr<U2>>() , '0');
template<typename...>
static long test(...);
public:
static constexpr bool value
= IsSameT<decltype(test<T1,T2>(nullptr)),char>::value;
};
我的意思是...您的代码有几个问题。
没有特别的顺序。
1-如果调用
test<T1,T2>(nullptr)
,则显式地传递两种模板类型;因此,如果您为第二个参数定义第二种类型的test
template<typename U1, typename = decltype(T1_t() + T2_t())>
static char test(void *);
第二个从未使用过。
2-SFINAE与函数的模板参数一起使用;不带有该类的模板参数。所以,如果你尝试一些
template<typename U1, typename U2, typename = decltype(T1_t() + T2_t())>
static char test(void *);
SFINAE不起作用,因为您没有使用
U1
和U2
(方法的模板参数),而是使用了T1_t()
和T2_t()
,因此使用了T1
和T2
这两个类的模板参数。因此,我建议使用
using
Rr
删除引用 template <typename T>
using Rr = typename std::remove_reference<T>::type;
为了简化,通过返回的类型使用SFINAE
template<typename U1, typename U2>
static auto test(void *)
-> decltype(std::declval<Rr<U1>>() + std::declval<Rr<U2>>() , '0');
-编辑-
OP不能使用
std::declval()
。我使用mingw,并且由于未知原因无法识别declval
因此,我提出了一个总比没有强的琐碎替代品(没有
std::add_rvalue_reference<T>::type
,以防您无法使用它)template <typename T>
T declVal();
并且
HasPlusT
成为template <typename T1, typename T2>
struct HasPlusT
{
private:
template <typename T>
using Rr = typename std::remove_reference<T>::type;
template<typename U1, typename U2>
static auto test(void *)
-> decltype(declVal<Rr<U1>>() + declVal<Rr<U2>>() , '0');
template<typename...>
static long test(...);
public:
static constexpr bool value
= IsSameT<decltype(test<T1,T2>(nullptr)),char>::value;
};
-编辑2-
OP说
需要哪些修改才能支持对类模板的检查?我尝试对A类进行此操作,但似乎不起作用。请参阅初始文章。
这不是类模板的问题。
问题是您的
operator+()
用于A
类friend A<T> operator + (A<T> & a1, A<T> & a2)
{ return a1.add(a2); }
之所以不常见,是因为(正确地)是该类的
friend
函数,但接收到A<T>
对象的引用(左引用),而不是常量(通常是const
引用;第一个值可以是未引用的值) ,修改第一个收到的参数(危险)并通过复制返回。因此
HasPlusT
类失败,因为std::declval()
返回的r值引用的对象与要求l值的operator+
不匹配。我强烈建议您修改
operator+()
如下(a1
和a2
const
) friend A<T> operator+ (A<T> const & a1, A<T> const & a2)
{ A<T> ret{a1}; return ret.add(a2); }
或者,可能如下所示更好(
a1
不带&
,a2
const
) friend A<T> operator+ (A<T> a1, A<T> const & a2)
{ return a1.add(a2); }
并且您会看到
HasPlusT
再次起作用。关于c++ - 基于SFINAE的特征来确定是否支持运算符+,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51994788/