从Using SFINAE to check for global operator<<?和templates, decltype and non-classtypes收集信息,我收到了以下代码:
基本上,我将两个问题的代码合并为print
函数,如果它具有ostream
声明,或者另外调用to_string
方法。
取自问题1
namespace has_insertion_operator_impl {
typedef char no;
typedef char yes[2];
struct any_t {
template<typename T> any_t( T const& );
};
no operator<<( std::ostream const&, any_t const& );
yes& test( std::ostream& );
no test( no );
template<typename T>
struct has_insertion_operator {
static std::ostream &s;
static T const &t;
static bool const value = sizeof( test(s << t) ) == sizeof( yes );
};
}
template<typename T>
struct has_insertion_operator :
has_insertion_operator_impl::has_insertion_operator<T> {
};
取自问题2
template <typename T>
typename std::enable_if<has_insertion_operator<T>::value, T>::type
print(T obj) {
std::cout << "from print()" << std::endl;
}
template <typename T>
typename std::enable_if<!has_insertion_operator<T>::value, T>::type
print(T obj) {
std::cout << obj.to_string() << std::endl;
}
然后我的课程就像这样:
struct Foo
{
public:
friend std::ostream& operator<<(std::ostream & os, Foo const& foo);
};
struct Bar
{
public:
std::string to_string() const
{
return "from to_string()";
}
};
测试输出:
int main()
{
print<Foo>(Foo());
print<Bar>(Bar());
//print<Bar>(Foo()); doesn't compile
//print<Foo>(Bar()); doesn't compile
print(Foo());
print(Bar());
print(42);
print('a');
//print(std::string("Hi")); seg-fault
//print("Hey");
//print({1, 2, 3}); doesn't compile
return 0;
}
print(std::string("Hi"));
行seg-faults。谁能告诉我为什么?
答案 0 :(得分:7)
你的两个函数print()
都应该返回一些内容,而不是什么都不返回(与Q&amp;中的版本不同)。这是C ++ 11标准6.6.3 / 2段中未定义的行为。
如果print()
不应该返回任何内容,请让它返回void
,并将SFINAE约束放在模板参数列表中:
template <typename T,
typename std::enable_if<
has_insertion_operator<T>::value, T>::type* = nullptr>
void print(T obj) {
std::cout << "from print()" << std::endl;
}
template <typename T,
typename std::enable_if<
!has_insertion_operator<T>::value, T>::type* = nullptr>
void print(T obj) {
std::cout << obj.to_string() << std::endl;
}
以下是包含上述更改的live example。
如果您正在使用C ++ 03并且无法为函数模板参数指定默认参数,请避免将类型指定为std::enable_if
的第二个模板参数,或指定void
:
template <typename T>
typename std::enable_if<has_insertion_operator<T>::value>::type
print(T obj) {
std::cout << "from print()" << std::endl;
}
template <typename T>
typename std::enable_if<!has_insertion_operator<T>::value>::type
print(T obj) {
std::cout << obj.to_string() << std::endl;
}