static_assert в объявлении функции - PullRequest
5 голосов
/ 27 июня 2011

У меня довольно простая функция, использующая 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());
}

Ответы [ 2 ]

0 голосов
/ 28 июня 2011

Несмотря на то, что я могу неправильно понять вопрос, соответствует ли 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 необходимо повторить.

РЕДАКТИРОВАТЬ: Хотя я не совсем уверен, что это строго стандартное соответствие, помогает ли следующий обходной путь?( тест на идеоне )

template<typename T1, typename T2> void Add(T1 volatile&&, T2 volatile&&) {
    static_assert(sizeof(T1) == 0, "Must be addable!");
}
0 голосов
/ 27 июня 2011

Это невозможно из-за способа построения наборов кандидатов и SFINAE.Если бы вы могли утверждать до того, как сигнатура функции была полностью определена, то это потребовало бы, чтобы вы утверждали, прежде чем будет решено, что функция будет использоваться для этой функции.

Порядок шагов по существу:

  • Найти подходящие функции
  • Подставить выведенные параметры в аргументы функции и тип возвращаемого значения.
  • Отменить те, которые не работают (SFINAE)
  • Если одиноставьте, используйте это.

Когда вы хотите активировать assert?

Если вы запускаете его во время замены параметров, вы исключаете SFINAE, и если вы запускаете его в любое времяпосле этого тип возврата уже определен (слишком поздно).

...