воскресенье, 23 августа 2015 г.

[prog.c++11] В одном из случаев GCC 4.9/5.1 поддерживают шаблоны хуже MSVS2013/2015 :(

На мой дилетантский взгляд GCC всегда поддерживал C++ные шаблоны лучше и строже, чем VC++. Но вот наткнулся на ситуацию, когда GCC 4.9.2/5.1.0 отказывается компилировать код, который успешно проглатывают MSVS2013, MSVS2015, clang 3.4 и 3.6. При этом GCC 5.2.0 уже воспринимает этот код нормально.

Upd. Найден случай, когда все проглатывается.

GCC 4.9.2/5.1.0 не хочет воспринимать вызов шаблонной функции, у которой два параметра шаблона, а при вызове явно задается только один из них:

auto indicator = log_then_abort< signal >( 10u,
   []( const agent_t & ) {
      std::cout << "this a signal" << std::endl;
   } );

Вот здесь первый параметр шаблона указан явно -- это тип signal. А второй параметр шаблона компилятор должен был бы вывести самостоятельно. Но не может :(

На всякий случай, вот сама функция log_then_abort:

templatetypename M, typename L >
log_then_abort_app_indicator_t< M, L >
log_then_abort( unsigned int limit, L action )
{
   return log_then_abort_app_indicator_t< M, L >{ limit, std::move(action) };
}

Как раз при ее вызове явно указывается M, а вот L требуется вывести компилятору. VC++ и clang с этим успешно справляются. А вот у не самых древних версий GCC с этим проблемы. Хорошо хоть, что у 5.2.0 такой проблемы уже нет. Но это все равно не радует. Придется искать какой-то воркароунд.

PS. Если кого-то интересует, как GCC ругается, то вот его выхлоп полностью:

Compiling ./t1.cpp ...
./t1.cpp: In function 'void test()':
./t1.cpp:98:6: error: no matching function for call to 'log_then_abort(unsigned int, test()::)'
    } );
      ^
./t1.cpp:37:1: note: candidate: template log_then_abort_app_indicator_t log_then_abort(unsigned int, L)
 log_then_abort( unsigned int limit, L action )
 ^
./t1.cpp:37:1: note:   template argument deduction/substitution failed:

Такое ощущение, что компилятор хотел еще что-нибудь сказать, но не успел :)

PPS. А вот в таком варианте успешно работает:

struct limits_manager
{
   templatetypename M, typename L >
   static log_then_abort_app_indicator_t< M, L >
   log_then_abort( unsigned int limit, L lambda )
   {
      return log_then_abort_app_indicator_t< M, L >{
         limit, std::move(lambda) };
   }
};

auto indicator = limits_manager::log_then_abort< signal >( 10u,
   []( const agent_t & ) {
      std::cout << "this a signal" << std::endl;
   } );

Комментариев нет: