在不创建参数对象的情况下解析constexpr函数

Jay*_*ler 3 c++ templates argument-dependent-lookup constexpr c++11

精简版:

如果我有这样的功能:

constexpr bool has_some_property(Foo) { return true; }
Run Code Online (Sandbox Code Playgroud)

有没有办法调用函数而不必实际实例化Foo?如果Foo不是默认可构造的话?

长卷版本:

安东尼威廉姆斯最近写了一篇文章,详细介绍了一套为任何enum class专门用于特定模板的对象启用的免费功能.它遵循类似的方案中<ios>,std::is_error_code其中一个专门用于用户定义的类型或值的模板,以允许enable_if启用某些功能.在Anthony的案例中:

template<>
struct enable_bitmask_operators<my_bitmask>{
    static constexpr bool enable=true;
};
Run Code Online (Sandbox Code Playgroud)

然后在定义运算符时:

template<typename E>
typename std::enable_if<enable_bitmask_operators<E>::enable,E>::type
operator|(E lhs,E rhs){
Run Code Online (Sandbox Code Playgroud)

此技术的问题是模板特化必须与原始模板位于同一名称空间中,因此这不起作用:

namespace mystuff {
    enum class Foo {
        ...
    };

    // Fail: wrong namespace
    template<>
    struct enable_bitmask_operators<Foo> : std::true_type {}
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用一个constexpr函数,该函数可以在与类相同的命名空间中解析:

namespace mystuff {
    enum class Foo {
        ...
    };
    constexpr bool enable_bitmask_operators(Foo) { return true; }
Run Code Online (Sandbox Code Playgroud)

然后定义:

template<typename E>
typename std::enable_if<enable_bitmask_operators(E()),E>::type
operator|(E lhs,E rhs){
Run Code Online (Sandbox Code Playgroud)

关于这一点的好处是,即使使用嵌套类,它也能很好地工作.它的问题是它需要一个默认的可构造类.这适用于我们的enum class示例,但它不能作为专业化问题的一般解决方案.因此,如果我们想象尝试使用constexpr函数而不是其他类的模板特化,我们可能会遇到其他失败:

struct Foo {
    Foo() = delete;
};
constexpr bool has_some_property(Foo) { return true; }

...

// Fail for Foo...use of deleted function
template<typename E>
typename std::enable_if<has_some_property(E()),E>::type doStuff() {}
Run Code Online (Sandbox Code Playgroud)

它有点令人沮丧,因为我实际上并不需要创建该对象,我只是想在那里为ADL识别constexpr要调用的函数.我一直在想应该有一些方法我可以说我想要这个功能而不必实际创建对象.我玩过,std::declval但在这种情况下不起作用.

有没有人看到解决这个困境的方法?

Bar*_*rry 10

只是不要使用constexpr:

std::true_type has_some_property(Foo&& );
Run Code Online (Sandbox Code Playgroud)

请问Foo有吗?

using has_it = decltype(has_some_property(std::declval<Foo>()));
static_assert(has_it::value, "It should!");
Run Code Online (Sandbox Code Playgroud)

这是一个未评估的上下文,所以我们永远不必调用任何Foo构造函数.并且可以回避constexpr需要不断表达的问题.