LINUX.ORG.RU

Проверка доступа в c++

 ,


0

4

Объясните почему gcc выдаёт ошибку при компиляции следующего кода без определённого макроса USING_SIMPLE_BASE:

#ifndef USING_SIMPLE_BASE
	#include <tuple>
	#define BASE std::tuple_element<0,std::tuple<base>>::type
#else
	#define BASE base
#endif

struct base { protected: using type = int; };

template<typename> struct derived :private BASE
{
	using BASE::type;
};

int main() { return derived<int>::type(0); }
$ g++ -xc++ -std=c++14 -pedantic -o/dev/null -DUSING_SIMPLE_BASE test.cxx
$ #build success
$ g++ -xc++ -std=c++14 -pedantic -o/dev/null test.cxx
test.cxx: In function 'int main()':
test.cxx:15:35: error: 'using type = int' is protected within this context
 int main() { return derived<int>::type(0); }
                                   ^~~~
test.cxx:8:42: note: declared protected here
 struct base { protected: using type = int; };
                                          ^
$ #build failed
$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/6/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 6.3.0-18' --with-bugurl=file:///usr/share/doc/gcc-6/README.Bugs --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-6 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-6-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-6-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-6-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 6.3.0 20170516 (Debian 6.3.0-18)
Ошибка пропадает при определении указанного макроса. В чём здесь дело?

Deleted

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

Вот так кстати собирается:

#ifndef USING_SIMPLE_BASE
	#include <tuple>
	#define BASE std::tuple_element_t<0,std::tuple<base>>
#else
	#define BASE base
#endif

struct base { protected: using type = int; };

template<typename> struct derived :private BASE
{
	using BASE::type;
};

int main() { return derived<int>::type(0); }

Хотя, вроде бы это одно и тоже

template <std::size_t I, class T>
using tuple_element_t = typename tuple_element<I, T>::type;

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

Это тестовый пример, макрос я сюда для облегчения проверки воткнул. Там в способе указания базового класса дело: один способ работает как надо, а второй, по сути эквивалентный - нет

Deleted
()

два совершенно разных способа доступа, оба легальных

anonymous
()
Ответ на: комментарий от Deleted
cat 1.cpp
#ifndef USING_SIMPLE_BASE
	#include <tuple>
	#define BASE std::tuple_element_t<0,std::tuple<base>>
#else
	#define BASE base
#endif

struct base { protected: using type = int; };

template<typename> struct derived :private BASE
{
	using BASE::type;
};

int main() { return derived<int>::type(0); }
g++-7 -xc++ -std=c++14 -pedantic -o/dev/null 1.cpp
g++-7 -v
gcc version 7.2.0 (Ubuntu 7.2.0-1ubuntu1~16.04)
fsb4000 ★★★★★
()
Ответ на: комментарий от fsb4000

Ok, ясно. Кстати, я ошибся - у меня замена конкретно в этом примере тоже ситуацию исправляет. Но стоит чуть усложнить(сделать base шаблонным) - и ситуация повторяется:

#ifndef USING_SIMPLE_BASE
	#include <tuple>
	#define BASE std::tuple_element_t<0,std::tuple<base<T>>>
#else
	#define BASE base<T>
#endif

template<typename> struct base { protected: using type = int; };

template<typename T> struct derived :private BASE
{
	using typename BASE::type;
};

int main() { return derived<int>::type(0); }

Deleted
()
Ответ на: комментарий от Deleted

Да, g++ не собирает...

Внезапно, ещё тебе информации. MSVC 2017 нормально компилирует такой код без изменений(я даже ifdef убрал)

#include <tuple>
#define BASE std::tuple_element_t<0,std::tuple<base<T>>>

template<typename> struct base { protected: using type = int; };

template<typename T> struct derived :private BASE
{
	using typename BASE::type;
};

int main() 
{ 
	return derived<int>::type(0); 
}
1>------ Перестроение всех файлов начато: проект: Project134, Конфигурация: Release Win32 ------
1>main.cpp
1>Создание кода
1>All 1 functions were compiled because no usable IPDB/IOBJ from previous compilation was found.
1>Создание кода завершено
1>Project134.vcxproj -> C:\Users\fsb4000\Documents\Visual Studio 2017\Projects\Project134\Release\Project134.exe
========== Перестроение всех проектов: успешно: 1, с ошибками: 0, пропущено: 0 ==========

Update: clang++ тоже собирает. Только в g++ проблема...

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

Насчёт clang: ты ему пути к заголовкам указывал? Он вроде gcc-шные на линуксах по умолчанию использует. Без указания на первом примере у меня с ним тоже ошибка. А на оригинальном коде clang вообще падает)

Deleted
()
Ответ на: комментарий от Deleted

Нет, ничего не указывал. Да, заголовки gcc

Проверил ещё и изначальный код.

Ни clang++, ни MSVC 2017 его не собрали.

Вот что сказали

Ошибка	C2248	base::type: невозможно обратиться к protected typedef, объявленному в классе "base"
error: 'type' is a private member of 'base'
int main() { return derived<int>::type(0); }
                                  ^
1.cpp:10:36: note: constrained by private inheritance here
template<typename> struct derived :private BASE
                                   ^~~~~~~~~~~~
1.cpp:8:32: note: member is declared here
struct base { protected: using type = int; };
                               ^
1 error generated.

Но с std::tuple_element_t clang++ и MSVC2017 собирают код и шаблонный код...

clang version 6.0.0 (trunk)
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/i686-linux-gnu/7
Found candidate GCC installation: /usr/bin/../lib/gcc/i686-linux-gnu/7.2.0
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/7
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/7
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/7.2.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7.2.0
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Candidate multilib: x32;@mx32
Selected multilib: .;@m64

Мистика...

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

Да, у меня также... ЧСХ, public inheritance вот от этого:

constrained by private inheritance here

тоже не помогает

$ cat test-2.cxx
#ifndef USING_SIMPLE_BASE
	#include <tuple>
	#define BASE std::tuple_element<0,std::tuple<base>>::type
#else
	#define BASE base
#endif

struct base { protected: using type = int; };

template<typename> struct derived :public BASE
{
	using BASE::type;
};

int main() { return derived<int>::type(0); }
$ 
$ clang++ -xc++ -std=c++14 -pedantic -o/dev/null test-2.cxx
test-2.cxx:15:35: error: 'type' is a protected member of 'base'
int main() { return derived<int>::type(0); }
                                  ^
test-2.cxx:8:32: note: declared protected here
struct base { protected: using type = int; };
                               ^
1 error generated.

Deleted
()
Ответ на: комментарий от fsb4000

никакой мистики не вижу, может вы уже вместе с автором изучите правила наследования и таплы ?

anonymous
()
Ответ на: комментарий от anonymous

никакой мистики не вижу, может вы уже вместе с автором изучите правила наследования и таплы ?

Одни компиляторы собирают код, другие нет. Видимо не только мы с dllmain, но и часть компиляторостроителей не изучила правила наследования :)

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

покажите код который компилируется в одном и не компилируется в другом, причем каждый из компилеров должен быть последней версии

anonymous
()
Ответ на: комментарий от anonymous

покажите код который компилируется в одном и не компилируется в другом, причем каждый из компилеров должен быть последней версии

Чуть выше можно увидеть

#include <tuple>
#define BASE std::tuple_element_t<0,std::tuple<base<T>>>

template<typename> struct base { protected: using type = int; };

template<typename T> struct derived :private BASE
{
	using typename BASE::type;
};

int main() 
{ 
	return derived<int>::type(0); 
}

Компилируется на clang, MSVC.

Не компилируется на gcc(проверил и на версии 7.3.0 на linux manjaro).

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

что и ? у вас в начале темы наследование не дает доступа к декларации по правилам наследования

anonymous
()
Ответ на: комментарий от anonymous

Пишите подробнее. К protected-именам доступ _непосредственно_ из производного класса есть при любой схеме наследования. К тому же, наследование по public-схеме ситуацию не меняет

Deleted
()

Может быть баг. У них есть meta-bug на тему видимости и шаблонов. Но именно этого случая там вроде нет, так что можно попробовать зарепортить.

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

в случае тупла, он не может достучаться до протектного инта даже при паблик наследовании

anonymous
()
Ответ на: комментарий от Deleted

неймспейс под приватом не доступен в тупле, вот и вся малина, тупл может добраться только до паблик

anonymous
()
Ответ на: комментарий от anonymous

Кортеж там участвует только в одном: из него идёт выборка base-типа(строго говоря, 0-ой индекс здесь для простоты). Но наследование во всех случаях происходит от типа base, посмотрите вывод g++ -fdump-class-hierarchy для проверки

Deleted
()
Ответ на: комментарий от xaizek

Странно, что сразу два(а выше ещё и про msvc написали, т. е. три) компилятора практически на одном и том же спотыкаются

Deleted
()
Ответ на: комментарий от Deleted

кортеж пытается достучаться до типа, в бейсе который лежит в привате, вот и вся малина уберите приват, и сделайте паблик наследования, может тогда поймете

anonymous
()
Ответ на: комментарий от anonymous

кортеж пытается достучаться до типа, в бейсе который лежит в привате

Нет, смотрите внимательнее: кортеж до base::type добраться и не пробует - из него сам base выбирается и на этом участие std::tuple<> заканчивается. Либо я не понял мысль - опишите подробнее, на пальцах, так сказать.

уберите приват, и сделайте паблик наследования

Вариант, при котором и base::type, и derived<>::base в public доступе, конечно, заработает, но я именно о protected/private именах

Deleted
()
Ответ на: комментарий от Deleted

давайте все ваше упростим до https://ideone.com/UAA2ek

struct base { protected: using type = int; };

int main() { return base::type(0); }
prog.cpp: In function ‘int main()’:
prog.cpp:4:27: error: ‘using type = int’ is protected within this context
 int main() { return base::type(0); }
                           ^~~~
prog.cpp:2:42: note: declared protected here
 struct base { protected: using type = int; };
                                          ^
тупл это всего лишь обертка

anonymous
()
Ответ на: комментарий от anonymous

Вы упускаете одну важную деталь, а именно:

...
	using BASE::type;
...
Эта декларация(в public секции - модификатор доступа по умолчанию для struct) должна сделать имя type доступным в классе derived. Но при этом она, разумеется, остаётся недоступной через класс base. В соответствие с этим, обращение из main() выполняется именно посредством derived<int>::type. Сомнений в том, что обращение base::type в контексте main() будет неверным, у меня не возникает

Deleted
()
Ответ на: комментарий от Deleted
...
	using BASE::type;
...

в этом месте оно уже не доступно, даже если наследование поменять с приват на паблик, к чему дальше его использовать ?

anonymous
()
Ответ на: комментарий от anonymous

Это объявлено в непосредственно производном классе, protected имена в этом случае доступны при любом режиме наследования(в т. ч. private). Пример без кортежа(в котором схема наследования та же самая) работает, как и ожидалось

Deleted
()
Ответ на: комментарий от Deleted

я устал вам объяснять что наследуясь от типа кортежа, наследования нет, потому что кортеж не может добраться до декларации, поскольку она(декларация) протектед для кортежа
надеюсь вы сможете самостоятельно разобраться

anonymous
()
Ответ на: комментарий от anonymous

Да, я тоже заметил, что мы по кругу ходить начинаем. В частности, я уже писал про кортежи. Ждём, в общем, может ещё кто выскажется

Deleted
()
Ответ на: комментарий от Deleted

кортеж не видет алияса потому что он протектед, так как является внешним для кортежа

anonymous
()
Ответ на: комментарий от Deleted

Можно затенять type.

#ifndef USING_SIMPLE_BASE
	#include <tuple>
	#define BASE std::tuple_element_t<0,std::tuple<base<T>>>
#else
	#define BASE base<T>
#endif

template<typename> struct base { protected: using type = int; };

template<typename T> struct derived :private BASE
{
	using type = typename BASE::type;
};

int main() { return derived<int>::type(0); }
Но видимо такое затенение разрешено. Ни gcc, ни clang не показали предупреждение при -Wshadow...

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

затенение разрешено

Конечно. Но в оригинальном коде ещё и несколько методов есть, с ними такое не прокатит)

-Wshadow

Только для переменных, ЕМНИП

Deleted
()

Похоже на баг GCC. Вот пример:


struct base
{
  protected:
    using type = int;
};

template< class T >
struct identity
{
    using type_ = T; // (1) work
//    using type  = T; // (2) don't work
};

struct derived : private base
{
  public:
    using typename identity< base >::type_::type; // (1) work

//    using typename identity< base >::type::type;  // (2) don't work
};

int main()
{
	return derived::type();
}

Ошибка возникает если тип base получен в результате метавычислений и типы названы одинаково.

anonymous
()
Ответ на: комментарий от anonymous

при этом еще баг и в кланге но студия жует молча ? зная какие в мс криворукие, я бы сказал наоборот, а ошибка в пересечении имен

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.