Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

has_pre_decrement
PrevUpHomeNext
template <class Rhs, class Ret=dont_care>
struct has_pre_decrement : public true_type-or-false_type {};

Inherits: If (i) rhs of type Rhs can be used in expression --rhs, and (ii) Ret=dont_care or the result of expression --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 prefix 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);
Rhs rhs;
f(--rhs); // is valid if has_pre_decrement<Rhs, Ret>::value==true

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

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

has_pre_decrement<Rhs, Ret>::value is a bool integral constant expression.

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

has_pre_decrement<long> inherits from true_type.

has_pre_decrement<int, int> inherits from true_type.

has_pre_decrement<int, long> inherits from true_type.

has_pre_decrement<double, double> inherits from true_type.

has_pre_decrement<double, int> inherits from true_type.

has_pre_decrement<bool> inherits from false_type.

has_pre_decrement<const int> inherits from false_type.

has_pre_decrement<void*> inherits from false_type.

has_pre_decrement<int, std::string> inherits from false_type.

See also: Operator Type Traits

Known issues:

  • This trait cannot detect whether prefix operator-- is public or not: if operator-- is defined as a private member of Rhs then instantiating has_pre_decrement<Rhs> will produce a compiler error. For this reason has_pre_decrement cannot be used to determine whether a type has a public operator-- or not.
    struct A { private: void operator--(); };
    boost::has_pre_decrement<A>::value; // error: A::operator--() 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 { };
    void operator--(const A&);
    struct B { operator A(); };
    boost::has_pre_decrement<A>::value; // this is fine
    boost::has_pre_decrement<B>::value; // error: ambiguous overload
    
  • There is an issue when applying this trait to template classes. If operator-- is defined but does not bind for a given template type, it is still detected by the trait which returns true instead of false. Example:
    #include <boost/type_traits/has_pre_decrement.hpp>
    #include <iostream>
    
    template <class T>
    struct contains { T data; };
    
    template <class T>
    bool operator--(const contains<T> &rhs) {
    	return f(rhs.data);
    }
    
    class bad { };
    class good { };
    bool f(const good&) { }
    
    int main() {
    	std::cout<<std::boolalpha;
    	// works fine for contains<good>
    	std::cout<<boost::has_pre_decrement< contains< good > >::value<<'\n'; // true
    	contains<good> g;
    	--g; // ok
    	// does not work for contains<bad>
    	std::cout<<boost::has_pre_decrement< contains< bad > >::value<<'\n'; // true, should be false
    	contains<bad> b;
    	--b; // compile time error
    	return 0;
    }
    
  • volatile qualifier is not properly handled and would lead to undefined behavior

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_pre_decrement.hpp>. Please note however, that detection is based on function signature only, in the case that the operator is a function template then has_pre_decrement cannot perform introspection of the template function body to ensure that the type meets all of the conceptual requirements of the actual code.

For older compilers (BOOST_TT_HAS_ACCURATE_BINARY_OPERATOR_DETECTION not defined) then there are a number of issues:

  • This trait cannot detect whether unary operator-- is public or not: if operator-- is defined as a private class member of type T then instantiating has_pre_decrement<T> will produce a compiler error. For this reason has_pre_decrement cannot be used to determine whether a type has a public operator-- or not.
  • volatile qualifier is not properly handled and would lead to undefined behavior
  • Capturless lambdas are not supported and will lead to a compiler error if has_pre_decrement is instantiated on the lambda type.
  • Scoped enum types are not supported and will lead to a compiler error if has_pre_decrement is instantiated on such a type.

PrevUpHomeNext