2016-08-26 7 views
8

Это вопрос до Detecting constexpr with SFINAE.SFINAE constexpr with std :: get

Я хочу определить, является ли элемент кортежа (или что-нибудь, что можно использовать с std::get) является constexpr. Поэтому я написал следующие похожие на то, что дало Xeo помощникам:

template<size_t> struct sfinae_true : std::true_type{}; 

template<size_t N, class T> 
auto check(const T& arg) -> sfinae_true<(std::get<N>(arg),N)>; 

template<size_t N, class> 
std::false_type check(...); 

Теперь мой тестовый код драйвера:

int main() 
{ 
    constexpr std::tuple<size_t, size_t> arg(4,5); 
    typedef decltype(check<0,decltype(arg)>(arg)) is_cexpr; 
    std::cout << "is constexpr? " << is_cexpr::value << '\n'; 
} 

Однако, это всегда печатает false для меня! Для того, чтобы проверить, что по какой-то причине ложной перегрузки не всегда будет вызван, я закомментирована ложной перегрузки и получите ошибку компиляции:

note: candidate template ignored: substitution failure [with N = 0, T = const std ::tuple]: non-type template argument is not a constant expression
auto check(const T& arg) -> sfinae_true<(std::get(arg),0)>;

Однако, я знаю, что я могу назвать std::get<N>(arg) и получить значение constexpr :

template<size_t N> 
class A{}; 

int main() 
{ 
    constexpr std::tuple<size_t, size_t> arg(4,5); 
    A<std::get<0>(arg)> a_val; 
} 

Это компилируется просто отлично.

  • Почему функция проверки не обнаруживает constexprness правильно?
  • Как исправить это?

Я тестировал это с помощью Clang 3.8.0 на Ubuntu 16.04.

редактировать:

В качестве дополнительного теста на основе ответа Сэма, я попробовал форму:

template<size_t N, class T> 
auto check(const T& arg) 
{ 
    return sfinae_true<(std::get<N>(arg)*0)>(); 
} 

Это избавляется от оператора запятая полностью, что GCC 5.4.0 компилирует просто отлично , но Clang 3.8.0 все еще жалуется. Интересно, что Кланг подчеркивает, что arg сам не является constexpr.

Почему эта проблема еще не решена? Каковы правила для аргументов функции constexpr?

+2

Проблема заключается в том, что параметр 'arg' не является' constexpr' ... – Jarod42

+1

(Чтобы немного расширить то, что я думаю @ Jarod42 означает: 'arg' является параметром функции никогда не рассматривается как постоянное выражение, даже если аргумент, который вы предоставляете функции, является постоянным выражением.) – dyp

+0

Как бы определить, будет ли результат вызова функции constexpr, если этот метод не работает? Ясно, что я могу использовать кортеж как значение constexpr, создав объект 'a_val'. – helloworld922

ответ

3

Это похоже на проблему с компилятором.

template<size_t N, class T> 
auto check(const T& arg) -> sfinae_true<(std::get<N>(arg),N)>; 

GCC не может скомпилировать это:

t.C:8:61: error: template argument 1 is invalid auto check(const T& arg) -> sfinae_true<(std::get(arg),N)>;

Но после настройки этого немного, я получаю ожидаемых результатов с GCC 6.1.1:

#include <tuple> 
#include <type_traits> 
#include <iostream> 

template<size_t> struct sfinae_true : std::true_type{}; 

template<size_t N, class T> 
auto check(const T& arg) 
{ 
    return sfinae_true<(std::get<N>(arg),N)>(); 
} 

template<size_t N, class> 
std::false_type check(...); 

int main() 
{ 
    constexpr std::tuple<size_t, size_t> arg(4,5); 
    typedef decltype(check<0,decltype(arg)>(arg)) is_cexpr; 
    std::cout << "is constexpr? " << is_cexpr::value << '\n'; 
} 

Это приводит к:

is constexpr? 1 

Обратите внимание, что запятые weren 'допускается в постоянных выражениях pre-C++ 11. Может быть, что-то осталось от той эпохи ...

+0

Я пробовал твой вклад в clang 3.8.0, и он не работает, но он работает с GCC 5.4.0. Интересно, что часть, которую clang выделяет как non-constexpr, не является оператором запятой, но тот факт, что 'arg' не является constexpr (я проверил это, удалив оператор запятой). – helloworld922

+0

В вашей версии по-разному указано другое поведение. SFINAE не применяется к выведенным типам возврата; SFINAE находится в непосредственном контексте только в том случае, когда вывод типа возврата требует довольно глубокого создания шаблона функции. – dyp

+0

Интересно, что @dyp, конечный результат - это предполагаемый результат. Параметр non-constexpr не привел к ошибке компиляции, а ожидаемому шаблону по умолчанию. Мне кажется, что возвращаемый тип функции шаблона выводится во время объявления, а затем участвует в разрешении SFINAE. –