Различное поведение boost::mpl::or_ и boost::mpl::and_?

Код ниже пытается проверить поведение короткого замыкания boost::mpl::or_ и boost::mpl::and_:

#include <vector>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/or.hpp>
#include <boost/mpl/and.hpp>
#include <boost/type_traits/is_scalar.hpp>

// Dummy is forward declared and never defined
template <class T> class dummy;

// If T is a scalar evaluates to T without trying to compute the result of 
// boost::mpl::is_scalar< dummy<T>, otherwise it fails at compile time.
template <class T> 
class testOr 
: public boost::mpl::eval_if< 
    boost::mpl::or_< boost::is_scalar<T>, boost::is_scalar< dummy<T> > >,
    boost::mpl::identity<T>,
    dummy<T>        
>
{};

// If T is not a scalar evaluates to T without trying to compute the result of 
// boost::mpl::is_scalar< dummy<T>, otherwise it should fail at compile time.
template <class T> 
class testAnd
: public boost::mpl::eval_if< 
    // It appears that is_scalar< dummy<T> > is not instantiated and the operation
    // evaluates to false
    boost::mpl::and_< boost::is_scalar<T>, boost::is_scalar< dummy<T> > >,
    dummy<T>,
    boost::mpl::identity<T>
>
{};

int main() {    

  static_assert(boost::is_same< testOr< double >::type, double>::type::value,"Fails at compile time");
  // The following line causes failures at compile time due to incomplete type definition
  //static_assert(boost::is_same< testOr< std::vector<double> >::type, double>::type::value,"Fails at compile time");

  static_assert(boost::is_same< testAnd< std::vector<double> >::type, std::vector<double> >::type::value,"Fails at compile time");
  // The following should cause failure at compile time due to incomplete type definition, but works instead!
  static_assert(boost::is_same< testAnd< double >::type , double >::type::value,"Fails at compile time");

return 0;
}

Хотя я ожидаю, что этот код завершится ошибкой во время компиляции из-за неполного определения типа, на самом деле он работает:

>icpc --version
icpc (ICC) 12.1.3 20120212
Copyright (C) 1985-2012 Intel Corporation.  All rights reserved.

>icpc -gcc-name=gcc-4.5 -std=c++0x -o ex-4.0.x ex-4.0.cc

Итак, суть, которую я хотел бы понять, заключается в следующем:

Есть ли несоответствие в том, как boost::mpl::or_ и boost::mpl::and_ оценивают свои аргументы, или, скорее всего, это ошибка в коде, которую я не могу отловить?


person Massimiliano    schedule 14.09.2012    source источник


Ответы (2)


Почему вы думаете, что второй аргумент or_ не будет оцениваться? is_scalar можно использовать с неопределенными типами.

Например, в этом случае вы также получаете свою ошибку.

// If T is not a scalar evaluates to T without trying to compute the result of 
// boost::mpl::is_scalar< dummy<T>, otherwise it should fail at compile time.
template <class T> 
class testAnd
: public boost::mpl::eval_if< 
    // It appears that is_scalar< dummy<T> > is not instantiated and the operation
    // evaluates to false
    boost::mpl::and_< boost::is_scalar<T>, boost::is_scalar< dummy<T> > >,
    boost::mpl::identity<T>,
    dummy<T>
>
{};

Так как boost::is_scalar<T> верно, а boost::is_scalar<dummy<T>> в вашем случае ложно, т.е.

Смотреть. http://liveworkspace.org/code/a792e18ca16a0410a67a6eee8c550bd9

person ForEveR    schedule 14.09.2012
comment
Это не то, что я пытаюсь сделать. Когда я пытаюсь принудительно выполнить оценку boost::is_scalar‹ dummy‹double› ›, mpl::or_ терпит неудачу во время компиляции, пытаясь создать экземпляр неполного типа, mpl::and_ вместо этого, похоже, оценивается как false. - person Massimiliano; 14.09.2012
comment
@Massimiliano в вашем mpl::and_, если первое выражение оценивается как ложное, второе выражение не будет оцениваться. в вашем mpl::or_, если первое выражение оценивается как истинное, второе выражение не будет оцениваться. Итак, где причина понизить мой ответ? - person ForEveR; 14.09.2012
comment
Пожалуйста, постарайтесь внимательно посмотреть на последние две строки перед возвратом в main. Первый оценивает boost::is_scalar‹ std::vector‹double›, что неверно (как вы сказали), но второй пытается оценить boost::is_scalar‹ double ›, что истинно, а затем я ожидаю boost::is_scalar‹ манекен‹двойной› › для оценки. - person Massimiliano; 14.09.2012
comment
Спасибо. Теперь я понял, где совершил ошибку: is_scalar работает с неопределенным типом, в то время как я ожидал, что он вызовет оценку dummy‹T›. - person Massimiliano; 14.09.2012

У вас есть логическая ошибка в ваших мыслях - || замкнет iif первый аргумент оценивается как true. is_scalar<std::vector<double>> равно false, что означает необходимость оценки второго аргумента. Напротив, && замкнется, если первым аргументом будет false, как было сказано выше.

person Xeo    schedule 14.09.2012