Следующий код не компилируется с ошибкой no member named 'foo' in 'B'
, несмотря на то, что это проблема только в контексте, который следует отбросить во время компиляции.
#include <type_traits>
struct A {
int foo() {
return 1;
}
};
struct B {
int bar() {
return 2;
}
};
static constexpr bool TEST = false;
using T = std::conditional_t<TEST, A, B>;
int main() {
T t{};
if constexpr (TEST) {
return t.foo();
} else {
return t.bar();
}
}
Что я могу сделать, чтобы включить такой код? Если бы я заменил constexpr макросами препроцессора, это, скорее всего, сработало бы нормально, не так ли?
Операторы можно отбросить, только если они находятся в зависимом контексте. Поместите это в шаблон функции, приняв тип T
, и все заработает.
https://en.cppreference.com/w/cpp/language/if рассказывает о вашей ситуации:
Вне шаблона отброшенный оператор полностью проверяется
Это говорит о том, что вы можете вставить его в шаблон, чтобы он работал:
template <typename U=T> int myMain()
{
U t{};
if constexpr (TEST) {
return t.foo();
} else {
return t.bar();
}
}
int main() {
return myMain();
}
Примечание. На самом деле все должно зависеть от параметра шаблона; если вы просто сохраните T t{};
, эта переменная на самом деле не является шаблонной, и компилятор снова просто снова будет жаловаться. Итак, мне пришлось предложить небольшой обходной путь — с точки зрения компилятора я мог передать любой U
, поэтому он понятия не имеет, каким будет t
, и поэтому он будет работать.
cppreference на самом деле объясняет это как
Если оператор constexpr if появляется внутри шаблонной сущности и если после создания экземпляра условие не зависит от значения, отброшенный оператор не создается при создании экземпляра включающего шаблона.
Однако их объяснение «зависимости от ценности» написано на каком-то языке, который, кажется, использует английские слова, но не передает много смысла. Итак, я приведу свое интуитивное объяснение плюс часть «отброшенный оператор не создается» из приведенной выше цитаты и пойду спать без головной боли.
поведение, отличающееся в зависимости от того, относится ли оно к параметру шаблона функции, является неожиданным. Мне любопытно узнать, почему было бы желательно оценить не выбранную ветку, но, тем не менее, это именно то, что я искал. Спасибо!
@keltek да, меня это тоже в какой-то момент поразило. Не исключено, что это еще одна уступка производителям компиляторов. Фактически, функционально if constexpr
вне шаблонов ощущается почти как обычно ìf
за исключением того, что код не создается даже без оптимизации — при оптимизации и постоянном условии в одной из веток также будет удален код, и мы также просто "проверь"...
if constexpr
работает только в шаблонах функций.main
не является шаблоном функции