Можно ли узнать, был ли параметр установлен по умолчанию

Внимание! Эта проблема касается только MSVS.

У меня есть эта подпись функции:

void do_somthing(std::vector<foo>&  bar={});

Можно ли различать эти два вызова функции:

Первый:

do_something()

Второй:

std::vector<foo> v;
do_something(v);

Другими словами, я хочу что-то вроде:

void do_somthing(std::vector<foo>&  bar={}){
    if(/* bar was defaulted*/){

    }
    else{

    }
}

EDIT: Фактический код:

template<class Tinput_iterator>
            Tmodel perform_fitting(Tinput_iterator begin_data, Tinput_iterator end_data, std::vector<Tpoint>& inliers = {});

person Humam Helfawi    schedule 26.02.2016    source источник
comment
Как насчет двух функций, одной с параметром (обычным, без значения по умолчанию) и одной без него?   -  person deviantfan    schedule 26.02.2016
comment
@deviantfan уверен, что это правильное решение, и именно это я и планирую сделать. Но мне было любопытно, можно ли это сделать в той же функции   -  person Humam Helfawi    schedule 26.02.2016
comment
@JamesAdkison, если бы он был установлен по умолчанию, это означает, что вывод этого параметра не нужен, поэтому я бы не вычислял его в функции и не снижал производительность.   -  person Humam Helfawi    schedule 26.02.2016
comment
Таким образом, параметр необходим, когда вызывающая сторона явно дает ему пустой vector? Что он будет делать с предоставленным пустым vector, чего не будет делать с пустым vector по умолчанию?   -  person James Adkison    schedule 26.02.2016
comment
@HumamHelfawi Вы можете использовать if(bar.empty()) return;   -  person NathanOliver    schedule 26.02.2016
comment
@HumamHelfawi, вы имеете в виду, что std::vector используется для хранения вывода? Есть ли причина не возврата по значению?   -  person TartanLlama    schedule 26.02.2016
comment
Похоже, вы хотите bool paramIsImportant в качестве другого параметра   -  person deviantfan    schedule 26.02.2016
comment
Я только что заметил, что вы отредактировали вопрос и удалили const, и вы используете его в качестве выходного параметра...   -  person James Adkison    schedule 26.02.2016
comment
@NathanOliver пусто в обоих случаях   -  person Humam Helfawi    schedule 26.02.2016
comment
@TartanLlama ага. плохой дизайн, который я не могу изменить сейчас   -  person Humam Helfawi    schedule 26.02.2016
comment
@JamesAdkison да, вы уведомили меня своим комментарием :)   -  person Humam Helfawi    schedule 26.02.2016
comment
@HumamHelfawi В любом случае ваш код недействителен на C++. Вы не можете привязать неконстантную ссылку lvalue к временной.   -  person juanchopanza    schedule 26.02.2016
comment
Погоди, этот код даже не скомпилируется. У вас не может быть ссылки lvalue на временный параметр, который является вашим параметром по умолчанию. Если вы измените на const&, то этот вопрос будет глупым, поскольку вы просто проверяете, является ли вектор empty(). Даже если вы передаете вектор с сайта вызова, если он пуст, вы ничего не можете сделать с вектором, поскольку он const.   -  person NathanOliver    schedule 26.02.2016
comment
Мне жаль, что я редактировал его из своего исходного кода и забыл сделать это хорошо. я отредактировал   -  person Humam Helfawi    schedule 26.02.2016
comment
Да, этот вопрос основан на ложной предпосылке.   -  person Galik    schedule 26.02.2016
comment
Этот код все равно не скомпилируется, так как вы пытаетесь привязать временную ссылку к lvalue.   -  person NathanOliver    schedule 26.02.2016
comment
@HumamHelfaw Фактический код не должен компилироваться, вы используете MSVC?   -  person TartanLlama    schedule 26.02.2016
comment
@HumamHelfawi Тогда он использует нестандартное расширение, на это не следует полагаться.   -  person TartanLlama    schedule 26.02.2016
comment
@HumamHelfawi Это нестандартное расширение, и вы должны прекратить его использовать. Это сделает ваш код не переносимым.   -  person NathanOliver    schedule 26.02.2016
comment
@TartanLlama Понятно! теперь это совершенно справедливо. Я выберу решение для двух функций и покоюсь с миром. Спасибо вам всем, ребята :)   -  person Humam Helfawi    schedule 26.02.2016


Ответы (3)


У меня есть эта подпись функции:

void do_somthing(std::vector<foo>&  bar=std::vector<foo>{});

Это не может компилироваться, за исключением опасных нестандартных настроек компилятора, от которых вам следует держаться подальше.

В частности, Visual C++ разрешает это, если /Za не указано, но с /W4 все равно выдает предупреждение вроде этого:

stackoverflow.cpp(6): warning C4239: nonstandard extension used: 'default argument': conversion from 'std::vector<foo,std::allocator<_Ty>>' to 'std::vector<foo,
std::allocator<_Ty>> &'
        with
        [
            _Ty=foo
        ]
stackoverflow.cpp(6): note: A non-const reference may only be bound to an lvalue
void do_somthing(std::vector<foo>&  bar=std::vector<foo>{}){
    if(/* bar was defaulted*/){

    }
    else{

    }
}

Даже если мы предположим, что вы действительно включили отсутствующий const для компиляции кода, ответ будет таким: нет, невозможно узнать, был ли bar установлен по умолчанию.

Что бы вы ни планировали здесь делать, вам придется найти совершенно другое решение.

person Christian Hackl    schedule 26.02.2016
comment
Хороший улов, я не понял, что параметр не-const. - person 5gon12eder; 26.02.2016

Нет, не напрямую. Параметр по умолчанию заменяется компилятором на месте вызова без какой-либо дополнительной информации.

Однако есть простое решение для достижения желаемого: используйте перегрузку вместо параметров по умолчанию.

namespace detail
{
  void
  do_something_impl(const std::vector<foo>& foos)
  {
    // Do things that always need to be done…
  }
}

void
do_something()
{
  // Do things specific to the no-argument case…
  detail::do_something_impl({});
}

void
do_something(const std::vector<foo>& foos)
{
  // Do things specific to the one-argument case…
  detail::do_something_impl(foos);
}

Если ваша логика требует более частого перехода — не только в начале или в конце функции — вы можете передать дополнительный логический параметр в detail::do_something_impl, который кодирует, из какой перегрузки она была вызвана.

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

person 5gon12eder    schedule 26.02.2016

Можно ли различать эти два вызова функции?

Нет. Вы можете проверить, пуст ли вектор, но иначе их никак не отличить.

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

person Rob L    schedule 26.02.2016