【问题标题】:static_assert in a function declaration函数声明中的 static_assert
【发布时间】:2011-06-27 18:16:02
【问题描述】:

我有一个使用static_assert 的非常简单的函数。问题是我想static_assert 函数声明中涉及的行为——特别是推断返回类型。似乎没有任何地方可以插入 static_assert 以便我可以在编译器无法推断返回类型之前触发它

到目前为止,我将返回类型推导和静态断言放在一个结构中。这将触发断言,这很好,但它仍然会在类型推导上产生错误,这是我想要消除的噪音。

#include <type_traits>
#include <functional>
#include <memory>
#include <map>
#include <iostream>
#include <string>
#include <cstdio>
#include <tuple>
#include <sstream>
#include <vector>
#include <algorithm>

template<typename T, typename X> struct is_addable {
    template<typename Test, typename Test2> static char test(decltype(*static_cast<Test*>(nullptr) + *static_cast<Test2*>(nullptr))*);
    template<typename Test, typename Test2> static int test(...);
    static const bool value = std::is_same<char, decltype(test<T, X>(nullptr))>::value;
};
template<typename T, typename X> struct is_addable_fail {
    static const bool value = is_addable<T, X>::value;
    static_assert(value, "Must be addable!");
    typedef decltype(*static_cast<T*>(nullptr) + *static_cast<X*>(nullptr)) lvalue_type;
};

template<typename T1, typename T2> auto Add(T1&& t1, T2&& t2) -> typename is_addable_fail<T1, T2>::lvalue_type {
    return std::forward<T1>(t1) + std::forward<T2>(t2);
}

struct f {};

int main() {
    std::cout << Add(std::string("Hello"), std::string(" world!"));
    Add(f(), f());
}

【问题讨论】:

    标签: visual-studio-2010 templates c++11 generic-programming static-assert


    【解决方案1】:

    这是不可能的,因为候选集的构建方式和 SFINAE。如果您可以在函数的签名完全确定之前断言,那么这将需要您在确定该函数是要使用的函数之前断言。

    步骤的顺序本质上是:

    • 查找匹配函数
    • 将推导的参数代入函数参数和返回类型。
    • 丢弃那些失败的 (SFINAE)
    • 如果还剩一个,就用那个。

    您希望断言何时触发?

    如果您在参数替换期间触发它,那么您将排除 SFINAE,如果您在此之后的任何时间触发它,则返回类型已经确定(为时已晚)。

    【讨论】:

    • 排除 SFINAE 对我来说很好。事实上,可以防止 SFINAE 或 ADL 的解决方案会更好。
    【解决方案2】:

    虽然我可能会误解这个问题, 像下面这样的SFINAE能达到目的吗?

    template<typename T = int> void Add(...) {
        static_assert(sizeof(T) == 0, "Must be addable!");
    }
    
    template<typename T1, typename T2> auto Add(T1&& t1, T2&& t2) ->
      decltype(std::forward<T1>(t1) + std::forward<T2>(t2)) {
        return std::forward<T1>(t1) + std::forward<T2>(t2);
    }
    

    这是对ideone 的测试。 缺点是Add必须重复。

    编辑: 虽然我不完全确定这是否严格符合标准,但 以下解决方法帮助? (a test on ideone)

    template<typename T1, typename T2> void Add(T1 volatile&&, T2 volatile&&) {
        static_assert(sizeof(T1) == 0, "Must be addable!");
    }
    

    【讨论】:

    • 但是报错信息中没有提到添加失败的模板类型。
    • 我明白了,虽然我不确定这真的对你有帮助,但请查看编辑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多