【问题标题】:Should decltype on a template value parameter trigger a SFINAE context?模板值参数上的 decltype 是否应该触发 SFINAE 上下文?
【发布时间】:2016-04-14 20:13:34
【问题描述】:

在尝试一些模板约束结构时,我在 Clang 3.7 中遇到了一个令人惊讶的行为:

struct constraint_success {};
struct constraint_failure {};

template<bool>
struct require_t {};

template<>
struct require_t<true> {
    static constexpr constraint_success* result = nullptr;
};

template<>
struct require_t<false> {
    static constexpr constraint_failure* result = nullptr;
};

template<bool Condition>
constexpr auto require = require_t<Condition>::result;

//A named dummy value, since we need a default
constexpr constraint_success* required = nullptr;

这个 decltype 在我的编译器中触发一个 SFINAE 上下文:

template<constraint_success* value>
using constraint = decltype(value);

相对于:

//template<constraint_success* value>
//using constraint = constraint_success*;

例子:

//define custom constraints
template<typename T>
constexpr auto Pointer = require<std::is_pointer<T>::value>;

template<typename T>
constexpr auto NotPointer = require<!std::is_pointer<T>::value>;

//constrain template parameters
template<typename T, constraint<Pointer<T>> = required>
void foo() {
    std::cout << "Hello, pointer!\n";
}

template<typename T, constraint<NotPointer<T>> = required>
void foo() {
    std::cout << "Hello, not pointer!\n";
}

int main() {
    foo<int*>();
    foo<int>();
    return 0;
}

这是标准要求,还是“幸运”的编译器错误?

Wandbox link

【问题讨论】:

    标签: c++ language-lawyer c++14 template-meta-programming sfinae


    【解决方案1】:

    诸如constraint 之类的别名模板会在使用它们的任何模板定义中被替换。它们的特殊之处在于:一旦提供了明确的参数,其他模板就会被替换。

    所以,这个声明:

    template<typename T, constraint<Pointer<T>> = required>
    void foo();
    

    大致相当于这个声明(区别是用static_cast 代替隐式转换):

    template<typename T, decltype(static_cast<constraint_success*>
                                             (require_t<std::is_pointer<T>>::result))
                                  = required>
    void foo();
    

    static_cast 无效时,这会产生 SFINAE。

    该效果很有用,基本上可以让您模拟即将推出的概念功能中的约束。但是,这种特殊的方法相当复杂,您并没有真正利用它。

    典型的 SFINAE 方法是这样的:

    template< typename T >
    std::enable_if_t< std::is_pointer< T >::value > foo();
    

    你可以更干净和聪明一点,从返回类型中删除 SFINAE——你现在想要的:

    template< typename T,
        std::enable_if_t< std::is_pointer< T >::value > * = nullptr >
    void foo();
    

    鉴于 Library Fundamentals TS 中的变量模板,这将符号对应于您的示例:

    template< typename T,
        std::enable_if_t< std::is_pointer_v< T > > * = nullptr >
    void foo();
    
     // constraint      < Pointer          <T>>      = required>
    

    真正的概念风格是这样的:

    template< typename T, std::enable_if_t< std::is_pointer< T >::value > * = nullptr >
    using Pointer = T;
    
    template< typename T >
    void foo( Pointer<T> );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-26
      • 2017-12-27
      • 2014-10-04
      • 1970-01-01
      • 1970-01-01
      • 2022-06-23
      • 1970-01-01
      相关资源
      最近更新 更多