| Home | Libraries | People | FAQ | More

### has_left_shift

    template <class Lhs, class Rhs=Lhs, class Ret=dont_care>
    struct has_left_shift : 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_left_shift<Lhs, Rhs, Ret>::value==true

If `Ret=void`, the return type is checked to be exactly `void`.

Header: `#include <boost/type_traits/has_left_shift.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_left_shift<Lhs, Rhs, Ret>::value_type` is the type `bool`.

> `has_left_shift<Lhs, Rhs, Ret>::value` is a `bool` integral constant expression.

> `has_left_shift<int>::value` is a `bool` integral constant expression that evaluates to `true`.

> `has_left_shift<long>` inherits from `true_type`.

> `has_left_shift<int, int, int>` inherits from `true_type`.

> `has_left_shift<const int, int>` inherits from `true_type`.

> `has_left_shift<std::ostream, int>` inherits from `true_type`.

> `has_left_shift<std::ostream, char*, std::ostream>` inherits from `true_type`.

> `has_left_shift<std::ostream, std::string>` inherits from `true_type`.

> `has_left_shift<int, double, bool>` inherits from `false_type`.

> `has_left_shift<int, int, std::string>` inherits from `false_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_left_shift.hpp>`. Please note however, that detection is based on function signature only, in the case that the operator is a function template then has_left_shift 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_left_shift.hpp>
    #include <iostream>

    template <class T>
    struct contains
    {
       T data;
       contains(const T& d) : data(d) {}
    };

    template <class T>
    contains<T> 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_left_shift< contains< good > >::value<<'\n'; // true
        contains<good> g;
        g&g; // ok
        // does not work for contains<bad>
        std::cout<<boost::has_left_shift< 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:

- This trait cannot detect whether binary `operator`<< is public or not: if `operator`<< is defined as a private member of `Lhs` then instantiating `has_left_shift<Lhs>` will produce a compiler error. For this reason `has_left_shift` cannot be used to determine whether a type has a public `operator`<< or not.

    struct A { private: A operator << (const A&); };
    boost::has_left_shift<A>::value; // error: A::operator << (const A&) is private

- There is an issue if the operator exists only for type `A` and `B` is convertible to `A`. In this case, the compiler will report an ambiguous overload.

    struct A { };
    A operator << (const A&, const A&);
    struct B { operator A(); };
    boost::has_left_shift<A>::value; // this is fine
    boost::has_left_shift<B>::value; // error: ambiguous overload

- `volatile` qualifier is not properly handled and would lead to undefined behavior