对于实际指针类型,用于检测类似(可取消引用)类型的指针的模板函数失败
Template function for detecting pointer like (dereferencable) types fails for actual pointer types
我正在尝试编写一种机制来检测类型是否是 指针类型 类型。我的意思是它可以通过 operator*()
和 operator->()
.
取消引用
我有三个不同的结构,它们相应地专门化:
is_pointer_like_dereferencable
检查 operator*()
is_pointer_like_arrow_dereferencable
检查 operator->()
is_pointer_like
简单地结合了 1 和 2
我为 int, int*, ...
等非模板类型和 std::vector<...>, std::shared_ptr<...>, ...
.
等模板类型添加了专门化
但是,我在实现is_pointer_like_arrow_dereferencable
的时候好像出错了。相关代码是
template <typename T, typename = void>
struct is_pointer_like_arrow_dereferencable : std::false_type
{
};
template <typename T>
struct is_pointer_like_arrow_dereferencable<T, std::enable_if_t<
std::is_pointer_v<T> ||
std::is_same_v<decltype(std::declval<T>().operator->()), std::add_pointer_t<T>>>
> : std::true_type
{
};
template <template <typename...> typename P, typename T, typename... R>
struct is_pointer_like_arrow_dereferencable<P<T, R...>, std::enable_if_t<
std::is_same_v<decltype(std::declval<P<T, R...>>().operator->()), std::add_pointer_t<T>>>
> : std::true_type
{
};
template <typename T>
constexpr bool is_pointer_like_arrow_dereferencable_v = is_pointer_like_arrow_dereferencable<T>::value;
第二个结构应该检查非模板类型是否是实际的指针类型,或者该类型是否有箭头运算符 returns 指向自身的指针。但是当我使用下面的代码测试该机制时,指针类型(如 int*
未被正确检测到)。这是为什么?
template <typename T>
struct Test
{
T& operator*()
{
return *this;
}
T* operator->()
{
return this;
}
};
void main()
{
bool
a = is_pointer_like_arrow_dereferencable_v<int>, // false
b = is_pointer_like_arrow_dereferencable_v<int*>, // false, should be true
c = is_pointer_like_arrow_dereferencable_v<vector<int>>, // false
d = is_pointer_like_arrow_dereferencable_v<vector<int>*>, // false, should be true
e = is_pointer_like_arrow_dereferencable_v<Test<int>>, // true
f = is_pointer_like_arrow_dereferencable_v<Test<int>*>, // false, should be true
g = is_pointer_like_arrow_dereferencable_v<shared_ptr<int>>, // true
h = is_pointer_like_arrow_dereferencable_v<shared_ptr<int>*>, // false, should be true
i = is_pointer_like_arrow_dereferencable_v<int***>; // false
}
is_pointer_like_dereferencable
结构仅在 std::is_same_v<...>
部分不同,它确实能正确检测实际指针类型。
它无法检测指针类型(std::is_pointer_v<...>
应该涵盖)这一事实对我来说没有任何意义。有人可以解释一下吗?
But when I test the mechanism with the code below, pointer types (like int* are not detected correctly). Why is that?
S.F.I.N.A.E.: 替换失败不是错误
因此,对于 int*
,从 decltype(std::declval<T>().operator->()
开始替换失败,并且不考虑专业化。所以是用一般形式,所以std::false
您应该编写 两个 专业化:一个或指针,一个用于 operator->()
启用 类。
奖励答案:我建议您传递一组辅助函数(仅声明)
,而不是 is_pointer_like_arrow_dereferencable
(过于复杂,恕我直言)
template <typename>
std::false_type is_pointer_like (unsigned long);
template <typename T>
auto is_pointer_like (int)
-> decltype( * std::declval<T>(), std::true_type{} );
template <typename T>
auto is_pointer_like (long)
-> decltype( std::declval<T>().operator->(), std::true_type{} );
所以is_pointer_like_arrow_dereferencable
可以简单地写成using
template <typename T>
using is_pointer_like_arrow_dereferencable = decltype(is_pointer_like<T>(0));
有助手is_pointer_like_arrow_dereferencable_v
template <typename T>
static auto const is_pointer_like_arrow_dereferencable_v
= is_pointer_like_arrow_dereferencable<T>::value;
以下是完整的工作示例
#include <type_traits>
#include <iostream>
#include <memory>
#include <vector>
template <typename>
std::false_type is_pointer_like (unsigned long);
template <typename T>
auto is_pointer_like (int)
-> decltype( * std::declval<T>(), std::true_type{} );
template <typename T>
auto is_pointer_like (long)
-> decltype( std::declval<T>().operator->(), std::true_type{} );
template <typename T>
using is_pointer_like_arrow_dereferencable = decltype(is_pointer_like<T>(0));
template <typename T>
static auto const is_pointer_like_arrow_dereferencable_v
= is_pointer_like_arrow_dereferencable<T>::value;
template <typename T>
struct Test
{
T & operator* () { return *this; }
T * operator-> () { return this; }
};
int main()
{
std::cout << is_pointer_like_arrow_dereferencable_v<int>
<< std::endl, // false
std::cout << is_pointer_like_arrow_dereferencable_v<int*>
<< std::endl, // true
std::cout << is_pointer_like_arrow_dereferencable_v<std::vector<int>>
<< std::endl, // false
std::cout << is_pointer_like_arrow_dereferencable_v<std::vector<int>*>
<< std::endl, // true
std::cout << is_pointer_like_arrow_dereferencable_v<Test<int>>
<< std::endl, // true
std::cout << is_pointer_like_arrow_dereferencable_v<Test<int>*>
<< std::endl, // true
std::cout << is_pointer_like_arrow_dereferencable_v<std::shared_ptr<int>>
<< std::endl, // true
std::cout << is_pointer_like_arrow_dereferencable_v<std::shared_ptr<int>*>
<< std::endl, // true
std::cout << is_pointer_like_arrow_dereferencable_v<int***>
<< std::endl; // true
}
首先,这个专业充其量是毫无意义的,但实际上是错误的:
template <template <typename...> typename P, typename T, typename... R>
struct is_pointer_like_arrow_dereferencable<P<T, R...>,
std::enable_if_t<
std::is_same_v<
decltype(std::declval<P<T, R...>>().operator->()),
std::add_pointer_t<T>>>
> : std::true_type
{ };
class 具有所有类型参数的模板特化在类指针方面没有任何特别之处。因此,您不需要对 P<T, R...>
进行任何不同于 T
的处理。
现在这个专精也有问题:
template <typename T>
struct is_pointer_like_arrow_dereferencable<T,
std::enable_if_t<
std::is_pointer_v<T> ||
std::is_same_v<decltype(std::declval<T>().operator->()), std::add_pointer_t<T>>>
> : std::true_type
{
};
首先,原始指针没有.operator->()
。这使得整个布尔表达式的格式不正确,从而导致整个特化被抛出。短路发生在逐个表达式的基础上,但每个表达式仍然必须有效。
其次,->
不必 return add_pointer_t<T>
。 std::vector<X>::iterator::operator->
return 是 X*
,而不是 iterator*
。所以那只是检查错误的东西。
我们可以让基本情况检查指针,只让特化检查所有类型的 .operator->
(无论它们是否是 class 模板特化):
template <typename T, typename = void>
struct is_pointer_like_arrow_dereferencable
: std::is_pointer<T>
{ };
template <typename T>
struct is_pointer_like_arrow_dereferencable<T,
void_t<decltype(std::declval<T>().operator->())>
>
: std::true_type
{ };
也就是说,is_pointer
可能还不够,因为 int*
是 "arrow dereferenceable" 没有意义。所以你可能想做这样的事情:
template <typename T, typename = void>
struct is_pointer_like_arrow_dereferencable
: std::false_type
{ };
template <typename T>
struct is_pointer_like_arrow_dereferencable<T*, void>
: std::disjunction<std::is_class<T>, std::is_union<T>>
{ };
或类似的。
我建议使用 std::experimental::is_detected
然后只需:
template <typename T> dereferencable_type = decltype(*declval<T>());
template <typename T> arrow_type = decltype(declval<T>().operator->());
template <typename T> is_dereferencable =
std::experimental::is_detected<dereferencable_type, T>;
template <typename T> has_arrow = std::experimental::is_detected<arrow_type, T>;
然后组成那些特征:
template <typename T>
using is_pointer_like_dereferencable = is_dereferencable<T>;
template <typename T>
is_pointer_like_arrow_dereferencable = std::disjunction<std::is_pointer<T>, has_arrow<T>>;
template <typename T>
std::is_pointer_like = std::conjunction<is_pointer_like_dereferencable<T>,
is_pointer_like_arrow_dereferencable<T>>;
根据 Jarod42 的回答(我无法编译),我创建了以下代码片段 (C++17),
#include "sys.h" // Required for libcwd (debug output).
#include "debug.h" // Required for libcwd (debug output).
#include <vector>
#include <memory>
#include <iostream>
//-----------------------------------------------------------------------------
// Start of implementation.
#include <experimental/type_traits>
#include <type_traits>
template<typename T> using dereferencable_type =
decltype(*std::declval<T>());
template<typename T> using arrow_type =
decltype(std::declval<T>().operator->());
template<typename T> using is_dereferencable =
std::experimental::is_detected<dereferencable_type, T>;
template<typename T> using has_arrow =
std::experimental::is_detected<arrow_type, T>;
template<typename T> using is_pointer_like_dereferencable =
is_dereferencable<T>;
template<typename T> using is_pointer_like_arrow_dereferencable =
std::disjunction<std::is_pointer<T>, has_arrow<T>>;
template <typename T> using is_pointer_like =
std::conjunction<is_pointer_like_dereferencable<T>,
is_pointer_like_arrow_dereferencable<T>>;
template<typename T> inline constexpr bool is_pointer_like_dereferencable_v =
is_pointer_like_dereferencable<T>::value;
template<typename T> inline constexpr bool is_pointer_like_arrow_dereferencable_v =
is_pointer_like_arrow_dereferencable<T>::value;
template<typename T> inline constexpr bool is_pointer_like_v =
is_pointer_like<T>::value;
// End of implementation
//-----------------------------------------------------------------------------
template<typename T>
struct TestNone
{
static int const n;
};
template<typename T>
struct TestRef : public TestNone<T>
{
T const& operator*() { return TestNone<T>::n; }
};
template<typename T>
struct TestArrow : public TestNone<T>
{
TestArrow const* operator->() { return this; }
};
template<typename T>
struct TestBoth : virtual public TestRef<T>, virtual public TestArrow<T>
{
};
//static
template<typename T>
int const TestNone<T>::n = 42;
template<typename T>
void test()
{
Dout(dc::notice|continued_cf, '"' <<
libcwd::type_info_of<T>().demangled_name() << "\" is ");
bool something = true;
if (is_pointer_like_v<T>)
Dout(dc::continued, "pointer-like.");
else
{
if (is_pointer_like_arrow_dereferencable_v<T>)
Dout(dc::continued, "arrow dereferencable; ");
else
something = is_pointer_like_dereferencable_v<T>;
if (is_pointer_like_dereferencable_v<T>)
Dout(dc::continued, "dereferencable; ");
}
if (!something)
Dout(dc::continued, "not a pointer or pointer-like.");
Dout(dc::finish, "");
}
int main()
{
Debug(NAMESPACE_DEBUG::init());
test<int>();
test<int*>();
test<std::vector<int>>();
test<std::vector<int>*>();
test<std::shared_ptr<int>>();
test<std::shared_ptr<int>*>();
test<std::shared_ptr<int***>>();
test<TestNone<int>>();
test<TestNone<int>*>();
test<TestRef<int>>();
test<TestRef<int>*>();
test<TestArrow<int>>();
test<TestArrow<int>*>();
test<TestBoth<int>>();
test<TestBoth<int>*>();
}
其中 sys.h
和 debug.h
是 'standard' headers 来自 git 子模块 cwds.
这将打印以下调试输出:
NOTICE : "int
" is not a pointer or pointer-like.
NOTICE : "int*
" is pointer-like.
NOTICE : "std::vector<int, std::allocator<int> >
" is not a pointer or pointer-like.
NOTICE : "std::vector<int, std::allocator<int> >*
" is pointer-like.
NOTICE : "std::shared_ptr<int>
" is pointer-like.
NOTICE : "std::shared_ptr<int>*
" is pointer-like.
NOTICE : "std::shared_ptr<int***>
" is pointer-like.
NOTICE : "TestNone<int>
" is not a pointer or pointer-like.
NOTICE : "TestNone<int>*
" is pointer-like.
NOTICE : "TestRef<int>
" is dereferencable;
NOTICE : "TestRef<int>*
" is pointer-like.
NOTICE : "TestArrow<int>
" is arrow dereferencable;
NOTICE : "TestArrow<int>*
" is pointer-like.
NOTICE : "TestBoth<int>
" is pointer-like.
NOTICE : "TestBoth<int>*
" is pointer-like.
我正在尝试编写一种机制来检测类型是否是 指针类型 类型。我的意思是它可以通过 operator*()
和 operator->()
.
我有三个不同的结构,它们相应地专门化:
is_pointer_like_dereferencable
检查operator*()
is_pointer_like_arrow_dereferencable
检查operator->()
is_pointer_like
简单地结合了 1 和 2
我为 int, int*, ...
等非模板类型和 std::vector<...>, std::shared_ptr<...>, ...
.
但是,我在实现is_pointer_like_arrow_dereferencable
的时候好像出错了。相关代码是
template <typename T, typename = void>
struct is_pointer_like_arrow_dereferencable : std::false_type
{
};
template <typename T>
struct is_pointer_like_arrow_dereferencable<T, std::enable_if_t<
std::is_pointer_v<T> ||
std::is_same_v<decltype(std::declval<T>().operator->()), std::add_pointer_t<T>>>
> : std::true_type
{
};
template <template <typename...> typename P, typename T, typename... R>
struct is_pointer_like_arrow_dereferencable<P<T, R...>, std::enable_if_t<
std::is_same_v<decltype(std::declval<P<T, R...>>().operator->()), std::add_pointer_t<T>>>
> : std::true_type
{
};
template <typename T>
constexpr bool is_pointer_like_arrow_dereferencable_v = is_pointer_like_arrow_dereferencable<T>::value;
第二个结构应该检查非模板类型是否是实际的指针类型,或者该类型是否有箭头运算符 returns 指向自身的指针。但是当我使用下面的代码测试该机制时,指针类型(如 int*
未被正确检测到)。这是为什么?
template <typename T>
struct Test
{
T& operator*()
{
return *this;
}
T* operator->()
{
return this;
}
};
void main()
{
bool
a = is_pointer_like_arrow_dereferencable_v<int>, // false
b = is_pointer_like_arrow_dereferencable_v<int*>, // false, should be true
c = is_pointer_like_arrow_dereferencable_v<vector<int>>, // false
d = is_pointer_like_arrow_dereferencable_v<vector<int>*>, // false, should be true
e = is_pointer_like_arrow_dereferencable_v<Test<int>>, // true
f = is_pointer_like_arrow_dereferencable_v<Test<int>*>, // false, should be true
g = is_pointer_like_arrow_dereferencable_v<shared_ptr<int>>, // true
h = is_pointer_like_arrow_dereferencable_v<shared_ptr<int>*>, // false, should be true
i = is_pointer_like_arrow_dereferencable_v<int***>; // false
}
is_pointer_like_dereferencable
结构仅在 std::is_same_v<...>
部分不同,它确实能正确检测实际指针类型。
它无法检测指针类型(std::is_pointer_v<...>
应该涵盖)这一事实对我来说没有任何意义。有人可以解释一下吗?
But when I test the mechanism with the code below, pointer types (like int* are not detected correctly). Why is that?
S.F.I.N.A.E.: 替换失败不是错误
因此,对于 int*
,从 decltype(std::declval<T>().operator->()
开始替换失败,并且不考虑专业化。所以是用一般形式,所以std::false
您应该编写 两个 专业化:一个或指针,一个用于 operator->()
启用 类。
奖励答案:我建议您传递一组辅助函数(仅声明)
,而不是is_pointer_like_arrow_dereferencable
(过于复杂,恕我直言)
template <typename>
std::false_type is_pointer_like (unsigned long);
template <typename T>
auto is_pointer_like (int)
-> decltype( * std::declval<T>(), std::true_type{} );
template <typename T>
auto is_pointer_like (long)
-> decltype( std::declval<T>().operator->(), std::true_type{} );
所以is_pointer_like_arrow_dereferencable
可以简单地写成using
template <typename T>
using is_pointer_like_arrow_dereferencable = decltype(is_pointer_like<T>(0));
有助手is_pointer_like_arrow_dereferencable_v
template <typename T>
static auto const is_pointer_like_arrow_dereferencable_v
= is_pointer_like_arrow_dereferencable<T>::value;
以下是完整的工作示例
#include <type_traits>
#include <iostream>
#include <memory>
#include <vector>
template <typename>
std::false_type is_pointer_like (unsigned long);
template <typename T>
auto is_pointer_like (int)
-> decltype( * std::declval<T>(), std::true_type{} );
template <typename T>
auto is_pointer_like (long)
-> decltype( std::declval<T>().operator->(), std::true_type{} );
template <typename T>
using is_pointer_like_arrow_dereferencable = decltype(is_pointer_like<T>(0));
template <typename T>
static auto const is_pointer_like_arrow_dereferencable_v
= is_pointer_like_arrow_dereferencable<T>::value;
template <typename T>
struct Test
{
T & operator* () { return *this; }
T * operator-> () { return this; }
};
int main()
{
std::cout << is_pointer_like_arrow_dereferencable_v<int>
<< std::endl, // false
std::cout << is_pointer_like_arrow_dereferencable_v<int*>
<< std::endl, // true
std::cout << is_pointer_like_arrow_dereferencable_v<std::vector<int>>
<< std::endl, // false
std::cout << is_pointer_like_arrow_dereferencable_v<std::vector<int>*>
<< std::endl, // true
std::cout << is_pointer_like_arrow_dereferencable_v<Test<int>>
<< std::endl, // true
std::cout << is_pointer_like_arrow_dereferencable_v<Test<int>*>
<< std::endl, // true
std::cout << is_pointer_like_arrow_dereferencable_v<std::shared_ptr<int>>
<< std::endl, // true
std::cout << is_pointer_like_arrow_dereferencable_v<std::shared_ptr<int>*>
<< std::endl, // true
std::cout << is_pointer_like_arrow_dereferencable_v<int***>
<< std::endl; // true
}
首先,这个专业充其量是毫无意义的,但实际上是错误的:
template <template <typename...> typename P, typename T, typename... R>
struct is_pointer_like_arrow_dereferencable<P<T, R...>,
std::enable_if_t<
std::is_same_v<
decltype(std::declval<P<T, R...>>().operator->()),
std::add_pointer_t<T>>>
> : std::true_type
{ };
class 具有所有类型参数的模板特化在类指针方面没有任何特别之处。因此,您不需要对 P<T, R...>
进行任何不同于 T
的处理。
现在这个专精也有问题:
template <typename T>
struct is_pointer_like_arrow_dereferencable<T,
std::enable_if_t<
std::is_pointer_v<T> ||
std::is_same_v<decltype(std::declval<T>().operator->()), std::add_pointer_t<T>>>
> : std::true_type
{
};
首先,原始指针没有.operator->()
。这使得整个布尔表达式的格式不正确,从而导致整个特化被抛出。短路发生在逐个表达式的基础上,但每个表达式仍然必须有效。
其次,->
不必 return add_pointer_t<T>
。 std::vector<X>::iterator::operator->
return 是 X*
,而不是 iterator*
。所以那只是检查错误的东西。
我们可以让基本情况检查指针,只让特化检查所有类型的 .operator->
(无论它们是否是 class 模板特化):
template <typename T, typename = void>
struct is_pointer_like_arrow_dereferencable
: std::is_pointer<T>
{ };
template <typename T>
struct is_pointer_like_arrow_dereferencable<T,
void_t<decltype(std::declval<T>().operator->())>
>
: std::true_type
{ };
也就是说,is_pointer
可能还不够,因为 int*
是 "arrow dereferenceable" 没有意义。所以你可能想做这样的事情:
template <typename T, typename = void>
struct is_pointer_like_arrow_dereferencable
: std::false_type
{ };
template <typename T>
struct is_pointer_like_arrow_dereferencable<T*, void>
: std::disjunction<std::is_class<T>, std::is_union<T>>
{ };
或类似的。
我建议使用 std::experimental::is_detected
然后只需:
template <typename T> dereferencable_type = decltype(*declval<T>());
template <typename T> arrow_type = decltype(declval<T>().operator->());
template <typename T> is_dereferencable =
std::experimental::is_detected<dereferencable_type, T>;
template <typename T> has_arrow = std::experimental::is_detected<arrow_type, T>;
然后组成那些特征:
template <typename T>
using is_pointer_like_dereferencable = is_dereferencable<T>;
template <typename T>
is_pointer_like_arrow_dereferencable = std::disjunction<std::is_pointer<T>, has_arrow<T>>;
template <typename T>
std::is_pointer_like = std::conjunction<is_pointer_like_dereferencable<T>,
is_pointer_like_arrow_dereferencable<T>>;
根据 Jarod42 的回答(我无法编译),我创建了以下代码片段 (C++17),
#include "sys.h" // Required for libcwd (debug output).
#include "debug.h" // Required for libcwd (debug output).
#include <vector>
#include <memory>
#include <iostream>
//-----------------------------------------------------------------------------
// Start of implementation.
#include <experimental/type_traits>
#include <type_traits>
template<typename T> using dereferencable_type =
decltype(*std::declval<T>());
template<typename T> using arrow_type =
decltype(std::declval<T>().operator->());
template<typename T> using is_dereferencable =
std::experimental::is_detected<dereferencable_type, T>;
template<typename T> using has_arrow =
std::experimental::is_detected<arrow_type, T>;
template<typename T> using is_pointer_like_dereferencable =
is_dereferencable<T>;
template<typename T> using is_pointer_like_arrow_dereferencable =
std::disjunction<std::is_pointer<T>, has_arrow<T>>;
template <typename T> using is_pointer_like =
std::conjunction<is_pointer_like_dereferencable<T>,
is_pointer_like_arrow_dereferencable<T>>;
template<typename T> inline constexpr bool is_pointer_like_dereferencable_v =
is_pointer_like_dereferencable<T>::value;
template<typename T> inline constexpr bool is_pointer_like_arrow_dereferencable_v =
is_pointer_like_arrow_dereferencable<T>::value;
template<typename T> inline constexpr bool is_pointer_like_v =
is_pointer_like<T>::value;
// End of implementation
//-----------------------------------------------------------------------------
template<typename T>
struct TestNone
{
static int const n;
};
template<typename T>
struct TestRef : public TestNone<T>
{
T const& operator*() { return TestNone<T>::n; }
};
template<typename T>
struct TestArrow : public TestNone<T>
{
TestArrow const* operator->() { return this; }
};
template<typename T>
struct TestBoth : virtual public TestRef<T>, virtual public TestArrow<T>
{
};
//static
template<typename T>
int const TestNone<T>::n = 42;
template<typename T>
void test()
{
Dout(dc::notice|continued_cf, '"' <<
libcwd::type_info_of<T>().demangled_name() << "\" is ");
bool something = true;
if (is_pointer_like_v<T>)
Dout(dc::continued, "pointer-like.");
else
{
if (is_pointer_like_arrow_dereferencable_v<T>)
Dout(dc::continued, "arrow dereferencable; ");
else
something = is_pointer_like_dereferencable_v<T>;
if (is_pointer_like_dereferencable_v<T>)
Dout(dc::continued, "dereferencable; ");
}
if (!something)
Dout(dc::continued, "not a pointer or pointer-like.");
Dout(dc::finish, "");
}
int main()
{
Debug(NAMESPACE_DEBUG::init());
test<int>();
test<int*>();
test<std::vector<int>>();
test<std::vector<int>*>();
test<std::shared_ptr<int>>();
test<std::shared_ptr<int>*>();
test<std::shared_ptr<int***>>();
test<TestNone<int>>();
test<TestNone<int>*>();
test<TestRef<int>>();
test<TestRef<int>*>();
test<TestArrow<int>>();
test<TestArrow<int>*>();
test<TestBoth<int>>();
test<TestBoth<int>*>();
}
其中 sys.h
和 debug.h
是 'standard' headers 来自 git 子模块 cwds.
这将打印以下调试输出:
NOTICE : "
int
" is not a pointer or pointer-like.
NOTICE : "int*
" is pointer-like.
NOTICE : "std::vector<int, std::allocator<int> >
" is not a pointer or pointer-like.
NOTICE : "std::vector<int, std::allocator<int> >*
" is pointer-like.
NOTICE : "std::shared_ptr<int>
" is pointer-like.
NOTICE : "std::shared_ptr<int>*
" is pointer-like.
NOTICE : "std::shared_ptr<int***>
" is pointer-like.
NOTICE : "TestNone<int>
" is not a pointer or pointer-like.
NOTICE : "TestNone<int>*
" is pointer-like.
NOTICE : "TestRef<int>
" is dereferencable;
NOTICE : "TestRef<int>*
" is pointer-like.
NOTICE : "TestArrow<int>
" is arrow dereferencable;
NOTICE : "TestArrow<int>*
" is pointer-like.
NOTICE : "TestBoth<int>
" is pointer-like.
NOTICE : "TestBoth<int>*
" is pointer-like.