C++ 增压测试增压检查等同于可转换为阵列的类型

C++ 增压测试增压检查等同于可转换为阵列的类型,c++,boost,template-meta-programming,c-strings,boost-test,C++,Boost,Template Meta Programming,C Strings,Boost Test,下面是一个使用Boost测试的简单程序,其行为“奇怪”: #定义BOOST\u TEST\u DYN\u链接 #定义BOOST_TEST_模块foo #包括 C类 { 公众: C(char*str):m_str(str){} 运算符char*()常量{return m_str;} char*get()常量{return m_str;} 私人: char*m_str; }; 增压自动测试案例(测试1) { 字符s1[]=“你好”; 字符s2[]=“你好”; C c1(s1); C c2(s2);

下面是一个使用Boost测试的简单程序,其行为“奇怪”:

#定义BOOST\u TEST\u DYN\u链接
#定义BOOST_TEST_模块foo
#包括
C类
{
公众:
C(char*str):m_str(str){}
运算符char*()常量{return m_str;}
char*get()常量{return m_str;}
私人:
char*m_str;
};
增压自动测试案例(测试1)
{
字符s1[]=“你好”;
字符s2[]=“你好”;
C c1(s1);
C c2(s2);
BOOST_CHECK_EQUAL(s1,s2);//检查1:通过
BOOST_CHECK_EQUAL(c1,c2);//检查2:失败(为什么?)
BOOST_CHECK_EQUAL(c1.get(),c2.get());//检查3:通过
}
如果您运行此命令,在比较c1和c2时,它将报告一个失败,而此时它似乎应该通过。原因是Boost测试中的代码(我使用的是1.51):

//这是为检查2而调用的
模板
谓词\u结果等于\u impl(左常量和左,右常量和右)
{
返回左==右;
}
//这是检查1和3时需要的
谓词\u结果BOOST\u TEST\u DECL equal\u impl(字符常量*左,字符常量*右);
内联谓词_result equal_impl(char*left,char*right){return equal_impl(static_cast(left),static_cast(right));}
//这决定了调用哪个比较器
结构相等\u impl\u frwd{
//这是检查2和3时需要的
模板
内联谓词结果
调用impl(左常量&左,右常量&右,mpl::false)常量
{
返回equal_impl(左、右);
}
//这是支票1
模板
内联谓词结果
调用impl(Left const&Left,Right const&Right,mpl::true)const
{
返回(*this)(右和左[0]);
}
模板
内联谓词结果
运算符()(左常量和左常量,右常量和右常量)常量
{
typedef typename是_数组::type left_是_数组;
返回调用_impl(左、右、左_为_数组());
}
};
因此,首先,BOOST_CHECK_EQUAL在编译时决定参数是否为数组。在检查1中,它们是,数组降级为指针。然后决定如何比较参数。如果参数的类型为char*,它将它们作为C字符串进行比较。否则,它使用运算符==。所以问题是C类不是char*,所以检查2是使用操作符==完成的。但是C类没有运算符==,因此编译器决定隐式地将c1和c2转换为char*,此时定义了运算符==,但将它们作为地址而不是C字符串进行比较

因此,我们最终遇到了一个相当奇怪的情况:Boost测试旨在始终将char*参数作为C字符串进行比较,但它不知道比较c1和c2的唯一方法是将它们转换为char*


我的问题是,我们如何在这里做得更好?例如,有没有一种方法可以在编译时理解,当为c1和c2调用运算符==时,它将使用它们到char*的隐式转换?这有点像在编译时使用decltype()计算表达式的返回类型,只是我们需要计算表达式的参数类型(即
c1==c2
)。

我认为您不能真正支持这种情况,因为我能想到的所有SFINAE技术都会遇到不明确的重载

事实上,这正是Boost类型特征的限制:

如果运算符仅针对类型A存在,并且B可转换为A,则会出现问题。在这种情况下,编译器将报告不明确的重载

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE foo
#include <boost/test/unit_test.hpp>

class C
{
public:
  C(char* str) : m_str(str) {}
  operator char*() const { return m_str; }
  char* get() const { return m_str; }

private:
  char* m_str;
};


BOOST_AUTO_TEST_CASE(test1)
{
  char s1[] = "hello";
  char s2[] = "hello";
  C c1(s1);
  C c2(s2);
  BOOST_CHECK_EQUAL(s1, s2); // check 1: passes
  BOOST_CHECK_EQUAL(c1, c2); // check 2: fails (why?)
  BOOST_CHECK_EQUAL(c1.get(), c2.get()); // check 3: passes
}
// this is called for check 2
template <class Left, class Right>
predicate_result equal_impl( Left const& left, Right const& right )
{
    return left == right;
}

// this is called for checks 1 and 3
predicate_result        BOOST_TEST_DECL equal_impl( char const* left, char const* right );
inline predicate_result equal_impl( char* left, char* right )       { return equal_impl( static_cast<char const*>(left), static_cast<char const*>(right) ); }

// this decides which comparator to call
struct equal_impl_frwd {
    // this is called for checks 2 and 3
    template <typename Left, typename Right>
    inline predicate_result
    call_impl( Left const& left, Right const& right, mpl::false_ ) const
    {
        return equal_impl( left, right );
    }

    // this is called for check 1
    template <typename Left, typename Right>
    inline predicate_result
    call_impl( Left const& left, Right const& right, mpl::true_ ) const
    {
        return (*this)( right, &left[0] );
    }

    template <typename Left, typename Right>
    inline predicate_result
    operator()( Left const& left, Right const& right ) const
    {
        typedef typename is_array<Left>::type left_is_array;
        return call_impl( left, right, left_is_array() );
    }
};