template <class Lhs, class Rhs=Lhs, class Ret=dont_care>
struct has_logical_and : public true_type-or-false_type
{};
Inherits: If (i) lhs
of type Lhs
and rhs
of type Rhs
can be used in expression lhs&&rhs
,
and (ii) Ret=dont_care
or the result of expression
lhs&&rhs
is convertible to Ret
then inherits from true_type,
otherwise inherits from false_type.
The default behaviour (Ret=dont_care
)
is to not check for the return value of binary operator&&
. If Ret
is different from the default dont_care
type, the return value is checked to be convertible to Ret
.
Convertible to Ret
means
that the return value of the operator can be used as argument to a function
expecting Ret
:
void f(Ret); Lhs lhs; Rhs rhs; f(lhs&&rhs); // is valid if has_logical_and<Lhs, Rhs, Ret>::value==true
If Ret=void
, the return type is checked to be exactly
void
.
Header: #include
<boost/type_traits/has_logical_and.hpp>
or #include <boost/type_traits/has_operator.hpp>
or #include <boost/type_traits.hpp>
Compiler Compatibility: Requires working SFINAE (i.e. BOOST_NO_SFINAE is not set). Only a minority of rather old compilers do not support this.
Examples:
has_logical_and<Lhs, Rhs, Ret>::value_type
is the typebool
.
has_logical_and<Lhs, Rhs, Ret>::value
is abool
integral constant expression.
has_logical_and<int>::value
is abool
integral constant expression that evaluates totrue
.
has_logical_and<bool>
inherits fromtrue_type
.
has_logical_and<int, int, bool>
inherits fromtrue_type
.
has_logical_and<int, int, long>
inherits fromtrue_type
.
has_logical_and<int, double, bool>
inherits fromtrue_type
.
has_logical_and<const int, int>::value
inherits fromtrue_type
.
has_logical_and<int, int, std::string>
inherits fromfalse_type
.
See also: Operator Type Traits
Known issues:
For modern compilers (those that support arbitrary SFINAE-expressions and
decltype/declval) this trait offers near perfect detection. In this situation
the macro BOOST_TT_HAS_ACCURATE_BINARY_OPERATOR_DETECTION
will be defined after including <boost/type_traits/has_logical_and.hpp>
.
Please note however, that detection is based on function signature only,
in the case that the operator is a function template then has_logical_and
cannot perform introspection of the template function body to ensure that
the type meets all of the conceptual requirements of the actual code.
Example:
#include <boost/type_traits/has_logical_and.hpp> #include <iostream> template <class T> struct contains { T data; contains(const T& d) : data(d) {} }; template <class T> bool operator && (const contains<T> &lhs, const contains<T> &rhs) { return f(lhs.data, rhs.data); } class bad { }; class good { }; good f(const good&, const good&) { return /*something*/; } int main() { std::cout<<std::boolalpha; // works fine for contains<good> std::cout<<boost::has_logical_and< contains< good > >::value<<'\n'; // true contains<good> g; g&g; // ok // does not work for contains<bad> std::cout<<boost::has_logical_and< contains< bad > >::value<<'\n'; // true, should be false contains<bad> b; b&b; // compile time error return 0; }
For older compilers (BOOST_TT_HAS_ACCURATE_BINARY_OPERATOR_DETECTION
not defined) then there are a number of issues:
operator
&&
is public or not: if operator
&&
is defined as a private member of Lhs
then instantiating has_logical_and<Lhs>
will
produce a compiler error. For this reason has_logical_and
cannot be used to determine whether a type has a public operator
&& or not.
struct A { private: bool operator && (const A&); }; boost::has_logical_and<A>::value; // error: A::operator && (const A&) is private
A
and B
is convertible to A
.
In this case, the compiler will report an ambiguous overload.
struct A { }; bool operator && (const A&, const A&); struct B { operator A(); }; boost::has_logical_and<A>::value; // this is fine boost::has_logical_and<B>::value; // error: ambiguous overload
volatile
qualifier is not
properly handled and would lead to undefined behavior