#include <iostream>
struct bar; // forward declaration
class foo { // implicitly private
friend struct ::bar; // but bar is a friend
template<typename T = int>
static void static_function_template() {}
template<typename T = int>
void function_template() {}
template<typename T = int>
class class_template {
static void static_function() {}
void function() {}
static T static_value;
T value;
};
};
struct bar { // implicitly public
// some alias templates referring to class foo:
template<typename T> using type01 = decltype(foo::static_function_template<T>());
template<typename T> using type02 = decltype(foo::static_function_template<>());
template<typename T> using type03 = decltype(foo::static_function_template<T>);
template<typename T> using type04 = decltype(foo().function_template<T>());
template<typename T> using type05 = decltype(foo().function_template<>());
template<typename T> using type06 = decltype(foo::class_template<T>::static_function());
template<typename T> using type07 = decltype(foo::class_template<>::static_function());
template<typename T> using type08 = decltype(foo::class_template<T>::static_function);
template<typename T> using type09 = decltype(foo::class_template<T>().function());
template<typename T> using type10 = decltype(foo::class_template<>().function());
// check (has direct access to bar)
template<template<typename> class TT, typename T, typename = TT<T>>
static void check(int) { std::cout << "> can be instantiated "; }
template<template<typename> class TT, typename T>
static void check(...) { std::cout << "> can NOT be instantiated "; }
};
// check (has no direct access to bar)
template<template<typename> class TT, typename T, typename = TT<T>>
void check(int) { std::cout << "> can be instantiated "; }
template<template<typename> class TT, typename T>
void check(...) { std::cout << "> can NOT be instantiated "; }
int main() {
#ifdef __clang__
std::cout << "-- compiled with clang --" << std::endl;
#endif
#ifdef _MSC_VER
std::cout << "-- compiled with MSVC --" << std::endl;
#endif
#ifdef __GNUC__
std::cout << "-- compiled with GCC --" << std::endl;
#endif
std::cout << std::endl;
std::cout << " inside of bar: outside of bar: " << std::endl;
std::cout << "type01 "; bar::check<bar::type01, int>(0); check<bar::type01, int>(0); std::cout << std::endl;
std::cout << "type02 "; bar::check<bar::type02, int>(0); check<bar::type02, int>(0); std::cout << std::endl;
std::cout << "type03 "; bar::check<bar::type03, int>(0); check<bar::type03, int>(0); std::cout << std::endl;
std::cout << "type04 "; bar::check<bar::type04, int>(0); check<bar::type04, int>(0); std::cout << std::endl;
std::cout << "type05 "; bar::check<bar::type05, int>(0); check<bar::type05, int>(0); std::cout << std::endl;
std::cout << "type06 "; bar::check<bar::type06, int>(0); check<bar::type06, int>(0); std::cout << std::endl;
std::cout << "type07 "; bar::check<bar::type07, int>(0); check<bar::type07, int>(0); std::cout << std::endl;
std::cout << "type08 "; bar::check<bar::type08, int>(0); check<bar::type08, int>(0); std::cout << std::endl;
std::cout << "type09 "; bar::check<bar::type09, int>(0); check<bar::type09, int>(0); std::cout << std::endl;
std::cout << "type10 "; bar::check<bar::type10, int>(0); check<bar::type10, int>(0); std::cout << std::endl;
std::cout << std::endl;
return 0;
}