Почему использование этой функции С++ дважды в одной строке вызывает ошибку компиляции?

Я столкнулся с некоторыми проблемами с попыткой реализовать в Visual С++ 2010 функцию шаблона макросов типа проверки равенства, которая связана с ошибкой в VS в отношении аргументов по умолчанию шаблона функции. Я исправил его, добавив значение параметра в дополнительную функцию, но теперь обнаружил, что не могу использовать эту функцию дважды в одной строке!

Заголовочный файл:

// example.h
#pragma once

#include <limits>

namespace myspace
{

// Need to define this separately to avoid a Visual Studio bug
template<typename T> T epsilon() { return std::numeric_limits<T>::epsilon(); }

// A generic equality test
template<typename T> inline bool smartEqual(
    const T &v1, 
    const T &v2, 
    const T &eps = epsilon<T>())
{
    return (v1 == v2);
}

// Template specialization for floating-point numbers
template<> bool smartEqual<float>(
    const float &v1, 
    const float &v2, 
    const float &eps);

} // namespace myspace

Исходный файл:

// example.cpp
#include "example.h"

using namespace std;
using namespace myspace;

// equal-macro specialization for floats using epsilon
template<> bool myspace::smartEqual<float>(
    const float &v1, 
    const float &v2, 
    const float &eps)
{
    return (fabs(v1 - v2) < eps);
}

int _tmain(int argc, _TCHAR* argv[])
{
    float a,b;
    bool x = smartEqual(a,b); // works ok
    bool x = smartEqual(a,b) && smartEqual(b,a); // error
    return 0;
}

Ошибка сообщается следующим образом:

------ Начало сборки: Project: test, Configuration: Debug Win32 ------
 test.cpp
c:\users\ninja\documents\visual studio 2010\projects\test\test\test.cpp(24): ошибка C2440: 'default argument': невозможно преобразовать из 'const float *' в 'const float &' < ш >          Причина: невозможно преобразовать из 'const float *' в 'const float'
         Нет никакого контекста, в котором это преобразование возможно

Строка оскорбления - это ту, где я пытаюсь дважды вызвать smartEqual(), используя логический И.

Я не понимаю, почему это происходит. Изменение "eps" от ссылочного типа до простого типа значения фиксирует его, но мне хотелось бы знать, что происходит.

Спасибо!

Ответы

Ответ 1

Думаю, вы теперь нажали эту ошибку VS10.

Ваш код компилирует OK на бета-версии VS11.

Возможно, вы можете избежать значения по умолчанию (что, по-видимому, является основной проблемой для VS10), изменив smartEqual на:

template<typename T> inline bool smartEqual(
    const T &v1, 
    const T &v2)
{
    return (v1 == v2);
}

и просто специализируется на float (и double) следующим образом:

template<> bool myspace::smartEqual<float>(
    const float &v1, 
    const float &v2)
{
    return (fabs(v1 - v2) < std::numeric_limits<float>::epsilon());
}


Другой вариант - изменить параметр epsilon для передачи по значению:

template<typename T> inline bool smartEqual(
    const T &v1, 
    const T &v2, 
    T eps = epsilon<T>())
{
    return (v1 == v2);
}

Ответ 2

не удалось выполнить код в VS2010, но ОК в компиляторе Intel. выглядит как ошибка в VS2010

Ответ 3

После некоторого рассмотрения я решил пойти с еще одним решением, которое предложил @Fraser (хотя я получил от него вдохновение) и написал свой собственный ответ:

  • Первое решение лишает меня гибкости в использовании пользовательского значения eps.
  • Второе решение с передачей по значению кажется неправильным, особенно если в будущем я решит использовать эту функцию для некоторых более надуманных типов.

Поскольку VS кажется чрезмерным с ошибками в отношении значений параметров по умолчанию (только в шаблонах?), кажется, что наиболее разумной задачей является устранение проблемы путем создания двух версий smartEqual; с и без eps (используя значение по умолчанию), что в значительной степени делает то же самое, если не так кратко:

// An equality test that doesn't require the value of eps, default will be used
template<typename T> inline bool smartEqual(
    const T &v1, 
    const T &v2)
{
    return (v1 == v2);
}

// Float specialization: return (fabs(v1 - v2) < std::numeric_limits<float>::epsilon());
template<> inline bool smartEqual<float>(
    const float &v1, 
    const float &v2);

// A custom-eps value equality test
template<typename T> inline bool smartEqual(
    const T &v1, 
    const T &v2, 
    const T &eps)
{
    return (v1 == v2);
}

// Float specialization: return (fabs(v1 - v2) < eps);
template<> bool smartEqual<float>(
    const float &v1, 
    const float &v2, 
    const float &eps);