От: | Quasi | ||
Дата: | 08.12.07 17:16 | ||
Оценка: | 141 (6) |
struct A
{
A(int){}; //not explicit
};
struct Possible
{
int func(A, int* = 0){return int();}
void func(long*) const{}
};
struct PossibleTemplate
{
template <typename T> T* func(T t)const {return &t;}
template <typename T> T* func(T* t){return t;}
};
struct Without{};
#define STATIC_ASSERT(condition) {int check[(condition)? 1 : -1];}
int main()
{
// В качестве типа второго шаблонного параметра is_call_possible передается тип функции R(Arg1, Arg2, ..),
// где ArgN - типы аргументов вызова метода, R - ожидаемый возвращаемый тип, или void, если это не интересует,
// параметры метода считаются lvalue
// проверяет, является ли выражение "оbj.func(i)" well-formed,
// где оbj - экземпляр класса Possible, i - const int lvalue
STATIC_ASSERT((is_call_possible<Possible, void (const int)>::value));
STATIC_ASSERT((!is_call_possible<Possible, void (int*)>::value));
// проверка вызова константного метода
STATIC_ASSERT((is_call_possible<const Possible, void (long*)>::value));
STATIC_ASSERT((!is_call_possible<const Possible, void (const int)>::value));
// проверяет, является ли выражение "A a(оbj.func(i));" well-formed,
// где оbj - экземпляр класса Possible, i - const int lvalue
STATIC_ASSERT((is_call_possible<Possible, A(const int)>::value));
STATIC_ASSERT((!is_call_possible<Possible, int*(const int)>::value));
STATIC_ASSERT((is_call_possible<PossibleTemplate, void (int)>::value));
STATIC_ASSERT((is_call_possible<PossibleTemplate, const void* (const int*)>::value));
STATIC_ASSERT((!is_call_possible<Without, int (int)>::value));
return 0;
}
template <typename type, typename call_details>
class is_call_possible
{
class size_class1{};
class size_class2{size_class1 m_[2];};
//добавляем перегруженный метод
template <typename size_class>
struct derived : public type
{
using type::func;
size_class func(...) const;
};
template <bool has, typename F>
struct impl
{
static const bool value = false;
};
template <typename arg1>
struct impl<true, void(arg1)>
{
// в случае, если в результате перегрузки выбран метод класса type,
// sizeof(тип возвращаемый методом) не может быть равен одновременно
// и sizeof(size_class1), и sizeof(size_class2)
static const bool value =
sizeof(((derived<size_class1>*)0)->func(*(arg1*)0))
!= sizeof(size_class1)
||
sizeof(((derived<size_class2>*)0)->func(*(arg1*)0))
!= sizeof(size_class2);
};
// и т.д.
// template <typename arg1, typename arg2, typename r>
// struct impl<true, void(arg1, arg2)> { ...
public:
//сначала проверяем наличие метода с помощью has_member
static const bool value = impl<has_member<type>::result, call_details>::value;
};
//Проверяем:
...........
int main()
{
STATIC_ASSERT((is_call_possible<Possible, void (const int)>::value));
STATIC_ASSERT((!is_call_possible<Possible, void (int*)>::value));
STATIC_ASSERT((is_call_possible<PossibleTemplate, void (int)>::value));
STATIC_ASSERT((!is_call_possible<Without, void (int)>::value));
return 0;
}
STATIC_ASSERT((is_call_possible<Possible, void (long*)>::value)); // ill-formed, потому что sizeof(void) - ill-formed
class void_exp_result{};
//Перегрузка оператора запятая 'operator,'
template <typename U> U const& operator,(U const&, void_exp_result);
template <typename U> U& operator,(U&, void_exp_result);
class double_size{ void_exp_result m_[2];};
template <typename result_type> result_type func();
#define STATIC_ASSERT(condition) {int check[(condition)? 1 : -1];}
int main()
{
STATIC_ASSERT(sizeof(void_exp_result) != sizeof(double_size));
STATIC_ASSERT((sizeof(func<double_size>(), void_exp_result()) == sizeof(double_size)));
STATIC_ASSERT((sizeof(func<void>(), void_exp_result()) == sizeof(void_exp_result)));
return 0;
}
13.3.1.2.9
If the operator is the operator ,, the unary operator &, or the operator ->, and there are no viable functions,
then the operator is assumed to be the built-in operator and interpreted according to clause 5.
..............
13.3.2.2
Second, for F to be a viable function, there shall exist for each argument an implicit conversion sequence
(13.3.3.1) that converts that argument to the corresponding parameter of F. If the parameter has reference
type, the implicit conversion sequence includes the operation of binding the reference, and the fact that a
reference to non-const cannot be bound to an rvalue can affect the viability of the function (see
13.3.3.1.4).
namespace details
{
template <typename type>
class void_exp_result
{};
//Перегрузка оператора запятая 'operator,'
template <typename type, typename U>
U const& operator,(U const&, void_exp_result<type>);
template <typename type, typename U>
U& operator,(U&, void_exp_result<type>);
template <typename src_type, typename dest_type>
struct clone_constness
{
typedef dest_type type;
};
template <typename src_type, typename dest_type>
struct clone_constness<const src_type, dest_type>
{
typedef const dest_type type;
};
}
template <typename type, typename call_details>
struct is_call_possible
{
private:
class yes {};
class no { yes m[2]; };
//добавляем перегруженный метод
struct derived : public type
{
using type::func;
no func(...) const;
};
//Учтем возможную константность типа класса
typedef typename details::clone_constness<type, derived>::type derived_type;
//Проверка результата выражения
template <typename T, typename due_type>
struct return_value_check
{
static yes deduce(due_type);
static no deduce(...);
//явные перегрузки в случае, если
//due_type имеет шаблонный конструктор
static no deduce(no);
static no deduce(details::void_exp_result<type>);
};
//Проверка результата выражения в случае,
//если не интересует возвращаемый тип метода
template <typename T>
struct return_value_check<T, void>
{
static yes deduce(...);
static no deduce(no);
};
template <bool has, typename F>
struct impl
{
static const bool value = false;
};
template <typename arg1, typename r>
struct impl<true, r(arg1)>
{
static const bool value =
sizeof(
return_value_check<type, r>::deduce(
//трюк с 'operator,'
(((derived_type*)0)->func(*(arg1*)0), details::void_exp_result<type>())
)
) == sizeof(yes);
};
// и т.д.
// template <typename arg1, typename arg2, typename r>
// struct impl<true, r(arg1, arg2)> { ...
public:
//сначала проверяем наличие метода с помощью has_member
static const bool value = impl<has_member<type>::result, call_details>::value;
};