Ошибка ODR в MSVC?

Эта программа печатает 1 1 вместо 1 2 при компиляции с MSVC (до VS 2015).

f1.cpp:

#include <functional>

static std::function<int ()> helper() {
    struct F { int operator()() { return 1; } };
    return F();
}

std::function<int ()> f1() { return helper(); }

f2.cpp:

#include <functional>

static std::function<int ()> helper() {
    struct F { int operator()() { return 2; } };
    return F();
}

std::function<int ()> f2() { return helper(); }

main.cpp:

#include <functional>
#include <iostream>

std::function<int ()> f1();
std::function<int ()> f2();

int main() {
    std::cout << f1()() << " " << f2()() << "\n";
}

Это как если бы разные определения F ломают ODR. Но не должны ли местные классы отличаться? Интересно, если мы заменим F с лямбда-функциями нет конфликта.

Так это ошибка компилятора или я неправильно понимаю правило одного определения?

1 ответ

Это явно ошибка в MSVC, так как все типы уникальны. Возможно для структур, определенных внутри некоторой функции (в этом случае helper) MSVC внутренне обрабатывает их, как если бы они были определены как helper::F в то время как если помощник статичен, он должен был сделать что-то вроде этого f1_cpp::helper::F вместо. В результате во время компоновки компоновщик видит две одинаково названные встроенные функции и объединяет их в одну.

Скорее всего, переупорядочив входные файлы вы можете получить 2 2 если вы не были довольны 1 1:)

Другие вопросы по тегам