Несовместимость трансляторов VS2017 и GCC

266
27 февраля 2018, 05:59

Добрый день.

Пишу простой код:

template<float(*math_fun)(float)> float run_math_fun(float arg) {
float ret = (*math_fun)(arg);
return ret;
}
float ddd() {
float a = 10.0;
return run_math_fun<&fabs>(a);
}

Транслятор VS2017 нормально транслирует этот код.

Транслятор GCC (из состава wxDev-C++) транслировать этот код отказывается и выдает следующую диагностику:

In function 'float ob_charspace::ddd()'::  
no matching function for call to 'run_math_fun(float&)' 
candidate is:
template<float (* math_fun)(float)> float ob_charspace::run_math_fun(float)
[Build Error]  [obj/ob7.o] Error 1

При этом саму функцию fabs транслятор GCC видит, понимает и, если вызвать fabs явно, то трансляция проходит нормально.

Вопрос:

  1. Что не нравится транслятору GCC в этом коде?

Спасибо.

Answer 1

fabs без namespace'а — это Си'шный вариант. В C++ надо сделать одно из трёх:

// 1; будет ли работать зависит от деталей реализации libm
#include <math.h>
// 2
#include <cmath>
using namespace std;
// 3
#include <cmath>
// ... 
return run_math_fun<&std::fabs>(a);

Последнее ИМХО предпочтительнее.

Answer 2

Согласно тому, что вы написали в комментариях, ради доступа к fabs вы включаете <math.h>. Однако простой эксперимент показывает, что при включении только <math.h> ваш код не компилируется ни в VS2017, ни в GCC, по одной и той же причине - не существует функции fabs, которая принимала бы аргумент типа float и возвращала бы результат типа float. Такой код и не должен компилироваться. Так что никакой несовместимости между компиляторами тут нет.

Для компилируемости вашего кода нужно включение <cmath>. Очевидно, что у вас в случае с VS2017 этот заголовочный файл оказался включенным тоже: он оказался неявно/случайно включенным через посредство каких-то других заголовочных файлов стандартной библиотеки С++. Это случайное включение <cmath> и приводило к компилируемости кода. В GCC это случайное включение не имеет места, вследствие чего в GCC код не компилируется.

Также следует заметить, что компоненты стандартной библиотеки в заголовочном файле <cmath> должны быть объявлены в пространстве имен std. Однако не оговаривается, каким образом это достигается: либо прямым объявлением этих имен в std, либо объявлением этих имен в глобальном пространстве имен и последующим переобъявлением их в std при помощи using-объявлений.

Компоненты стандартной библиотеки в заголовочном файле <math.h> должно быть объявлены в глобальном пространстве имен. Но совершенно симметричным образом этот заголовочный файл может внутреннее сначала объявлять эти имена в пространстве имен std, а затем переобъявлять их в глобальном пространстве имен при помощи using-объявлений.

Это значит, что доступность этих имен в "альтернативном" пространстве имен может варьироваться от реализации к реализации. Включая <cmath> вы гарантированно получите имена в в пространстве имен std, и при этом можете получить (а можете и не получить) эти имена в глобальном пространстве имен. С <math.h> ситуация обратная.

То есть подобный эффект может возникать и по таким причинам. Но эксперимент показывает, что в данном случае дело просто в неявном включении <cmath>.

READ ALSO
Как разбить файл на qt

Как разбить файл на qt

Имеется большой лог файлКак разбить лог файл на несколько файлов

241
Возвращаемый шаблонной функцией тип

Возвращаемый шаблонной функцией тип

В книге Стенли Липпмана(Базовый курс по с++) написано, что если тип возвращаемый шаблонной функцией отличается от типа параметра шаблона,...

257