LINUX.ORG.RU

Почему std::make_pair()/std::forward() так себя ведет

 


1

5
$cat test.h
#pragma once

#include <utility>

class Test
{
public:
    typedef std::pair<unsigned, void*> MyPair;
    MyPair foo();

    static const unsigned Invalid = (unsigned)-1;
};



$ cat test.cpp
#include "test.h"
#include <cstdio>

Test::MyPair Test::foo()
{
    // that's worked in c++11
    // const unsigned var = Invalid;
    // return std::make_pair(var, nullptr);

    // that's worked in c++11 too
    // return std::make_pair((unsigned)Invalid, nullptr);

    return std::make_pair(Invalid, nullptr);
}

int main(int argc, const char* argv[])
{
    Test test;
    Test::MyPair pair = test.foo();
    printf("first: %u, second: %p\n", pair.first, pair.second);

    return 0;
}


$ g++ test.cpp
$ ./a.out
first: 4294967295, second: 0x0


$ g++ -std=c++11 test.cpp
Undefined symbols for architecture x86_64:
  "Test::Invalid", referenced from:
      Test::foo() in t-f9f766.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)


Ткните носом в стандарт, где поясняется почему std::forward() не должен видеть статический мембер?

★★★★★

Последнее исправление: andreyu (всего исправлений: 2)

диванная гипотеза

Наверное, потому что в <c++11 оно работает по значению, а в c++11 пытается взять какую-нибудь там ссылку, а у тебя только declaration.

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от andreyu

Это декларация с инициализацией. Но не definition. Грубо говоря, память под такую переменную выделяется в секции .data конкретного объектного файла при компиляции того исходника, в котором у тебя definition.

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 1)
Ответ на: комментарий от intelfx

память под такую переменную выделяется в секции .data конкретного объектного файла при компиляции того исходника, в котором у тебя definition.

А что происходит в моем случае?

Полагаю, что каст помогает потому, что создается временная переменная?

andreyu ★★★★★
() автор топика
Ответ на: комментарий от andreyu

Да. Начиная с C++11 make_pair имеет прототип вида pair<V1, V2> make_pair(T1&&, T2&&) (где V1, V2 — это T1, T2 «после передачи по значению»), как T1 подставляется const unsigned&, производится свёртка ссылок (T& && == T&) и в итоге ты передаёшь в make_pair аргумент типа const unsigned& (а адреса у твоей переменной нет, потому что нет definition).

Когда ты делаешь каст, создаётся временная переменная с известным значением, как T1 подставляется unsigned&& и в итоге ты передаёшь в make_pair ссылку на временный объект.

А до C++11 у make_pair прототип без ссылок, и туда всегда передаётся значение.

intelfx ★★★★★
()
Последнее исправление: intelfx (всего исправлений: 2)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.