簡體   English   中英

參考類型的別名模板在SFINAE上下文中作為模板模板參數傳遞

[英]Alias template for reference type passed as template template argument in SFINAE context

我遇到了G ++ 6.1.0( -std=c++14 switch)的以下問題,我不明白為什么編譯器會拒絕代碼。

我有一個幫助程序結構is_well_formed ,它檢查提供的模板模板參數是否在將另一個提供的類型替換為它時形成良好:

template<template<typename> typename R, typename T, typename = void>
struct is_well_formed : std::false_type {};

template<template<typename> typename R, typename T>
struct is_well_formed<R, T, void_t<R<T>>> : std::true_type {};

我想檢查一個類型是否可引用。 所以我的想法是寫下面的內容:

// (#1)
template<class T>
using reference_t = T&;

static_assert(!is_well_formed<reference_t, void>::value, "Reference to void!?");

但是我收到編譯錯誤:

main.cpp: In instantiation of 'struct is_well_formed<reference_t, double>':
main.cpp:62:51:   required from here
main.cpp:54:20: error: type/value mismatch at argument 1 in template parameter list for 'template<template<class> class R, class T, class> struct is_well_formed'
  : std::false_type {};
                    ^
main.cpp:54:20: note:   expected a class template, got 'reference_t'
main.cpp:54:20: error: type/value mismatch at argument 1 in template parameter list for 'is_well_formed<R, T, <template-parameter-1-3> >::is_well_formed'
main.cpp:54:20: note:   expected a class template, got 'reference_t'

或者,以下使用相同的static_assert

// (#2)
template<class T>
using reference_t = void_t<T&>;

此外,以下作品真的讓我感到困惑:

// (#3)
template<class T>
using pointer_t = T*;

static_assert(is_well_formed<pointer_t, void>::value, "No pointer to void!?");

這三個別名有什么區別? void_t<T&>解決方案最優雅嗎? 或者是否可以修改is_well_formed幫助器結構以支持第一個reference版本?

編輯:我測試了MSVC“15”預覽4的代碼, (#1)(#3)工作包括斷言。 但是當我嘗試(#2) ,void引用的斷言不起作用,即在替換期間信息丟失並且永遠不會選擇false_type重載。 哪個編譯器是對的?

is_well_formed幫手對應can_apply從結構它曾經記錄堆棧溢出文檔頁面上SFINAE ,我只是刪除了參數包。 完整示例代碼:

#include <utility>

// Only defined in std for C++17
template <class...>
using void_t = void;

// (#1) Compiler error during substitution in is_well_formed
template<class T>
using reference_t = T&;

// (#2) Ok, asserts work
/*
template<class T>
using reference_t = void_t<T&>;
*/

// (#3) Ok, asserts work
template<class T>
using pointer_t = T*;

template<template<typename> typename R, typename T, typename = void>
struct is_well_formed 
    : std::false_type {};

template<template<typename> typename R, typename T>
struct is_well_formed<R, T, void_t<R<T>>> 
    : std::true_type {};

int main(int, char**)
{
    static_assert(is_well_formed<reference_t, double>::value, "No reference to double!?");
    static_assert(!is_well_formed<reference_t, void>::value, "Reference to void!?");

    static_assert(is_well_formed<pointer_t, double>::value, "No pointer to double!?");
    static_assert(is_well_formed<pointer_t, void>::value, "No pointer to void!?");

    return 0;
}

這可能是一個編譯器缺陷和用戶TC報告說,它在GCC的Bugzilla 這里看到這個帖子后。 用戶Jarod42提出

template<class T>
using reference = decltype(std::declval<T&>());

作為MSVC15和GCC 6.1.0的工作替代方案。 此外,他指出MSVC仍然需要長void_t定義

template <class...>
struct make_void { using type = void; };

template <typename... T>
using void_t = typename make_void<T...>::type;

而不是顯而易見的

template <class...>
using void_t = void;

這阻止了原始帖子中的選項(#2)工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM