Как создать кортеж ссылок на const?

Скажем, есть две функции:

void ff( const std::tuple<const int&> ) { }

template < typename TT >
void gg( const std::tuple<const TT&> ) { }

и вызывает следующие функции:

int xx = 0;
ff( std::tie( xx ) ); // passes
gg( std::tie( xx ) ); // FAILS !!

GCC 4.7.2 не может скомпилировать последнюю строку и сообщает об ошибке, например:

note:   template argument deduction/substitution failed:
note:   types ‘const TT’ and ‘int’ have incompatible cv-qualifiers
note:   ‘std::tuple<int&>’ is not derived from ‘std::tuple<const TT&>’

Первый вопрос: если это соответствует стандарту С++ 11, а если нет, то почему?

Кроме того, для преодоления этой проблемы необходимо передать кортеж ссылок const на gg вместо передачи набора неконстантных ссылок (что делает std::tie). Это можно сделать:

gg( std::tie( std::cref(x) ) );

однако дополнительный вызов std::cref является довольно утомительным, поэтому было бы здорово иметь что-то вроде ctie, которое создавало бы кортеж ссылок const.

Второй вопрос: нужно ли писать ctie вручную, и если да, то это лучший способ сделать это?

template < typename... T >
std::tuple<const T&...> ctie( const T&... args )
{
    return std::tie( args... );
}

Ответ 1

Первый вопрос: если это соответствует стандарту С++ 11, а если нет, то почему?

Это ожидаемое поведение. Во втором случае вывод аргумента шаблона невозможен, потому что нет T, так что tuple<const T&> становится tuple<int&>.

В первом случае это работает, потому что tuple<int&> неявно конвертируется в tuple<const int&>. Это пользовательское преобразование и, как таковое, не учитывается при выводе аргумента шаблона.

Ваши вопросы немного пахнут проблемой X/Y. Рассмотрите возможность публикации реального вопроса, который заставил вас искать решение, включающее эту комбинацию шаблонов функций/кортежей.

Ваш шаблон функции ctie выглядит нормально. Но имейте в виду, что такие вещи, как

auto t = ctie(5);

будет в основном создавать оборванную ссылку. Таким образом, вы можете ограничить ctie только lvalues.