Специализация шаблона на лямбде в C++ 0x

Что должно произойти, так это то, что «именованные элементы» добавляются как кажущиеся свойства объекта document. Это действительно плохая идея, так как позволяет именам элементов сталкиваться с реальными свойствами document.

IE затруднил ситуацию, добавив именованные элементы в качестве свойств объекта window. Это вдвойне плохо, потому что теперь вам нужно избегать именования ваших элементов после того, как захочет использовать какой-либо из объектов document или window, которые вы (или любой другой библиотечный код в своем проекте) захотите использовать.

Это также означает, что эти элементы видны как глобальные переменные. К счастью, в этом случае любые реальные глобальные объявления var или function в вашем коду затушевывают их, поэтому вам не нужно так беспокоиться об именах здесь, но если вы попытаетесь выполнить присвоение глобальной переменной с конфликтом имя и вы забудете объявить его var, вы получите сообщение об ошибке в IE, поскольку оно пытается присвоить значение самому элементу.

Обычно считается, что неправильная практика пропускает var, так как а также полагаться на названные элементы, которые видны на window или в виде глобальных. Придерживайтесь document.getElementById, который более широко поддерживается и менее неоднозначен. Вы можете написать тривиальную функцию обертки с более коротким именем, если вам не нравится ввод текста. В любом случае, нет смысла использовать кеш-поиск с id-элементом, поскольку браузеры обычно оптимизируют вызов getElementById, чтобы использовать быстрый поиск; все, что вы получаете, это проблемы, когда элементы меняются id или добавляются / удаляются из документа.

Opera скопировала IE, затем присоединился WebKit, и теперь обе ранее нестандартная практика размещения именованных элементов в document, и ранее применявшаяся только для IE практика помещать их в window, является стандартизированной HTML5, подход которой заключается в том, чтобы документировать и стандартизировать каждую ужасную практику, причиненную на нас авторами браузеров, делая их частью сети навсегда. Таким образом, Firefox 4 также будет поддерживать это.

Что такое «названные элементы»? Все, что имеет id, и все, что используется name для целей идентификации, то есть формы, изображения, привязки и несколько других, но не другие несвязанные экземпляры атрибута name, например, имена в полях ввода формы, имена параметров в или тип метаданных в . «Идентификация» name s - это те, которые следует избегать в пользу id.

25
задан Georg Fritzsche 6 April 2010 в 02:41
поделиться

2 ответа

Я думаю, что можно специализировать характеристики для лямбда-выражений и выполнять сопоставление с образцом по сигнатуре безымянного функтора. Вот код, который работает на g ++ 4.5. Хотя это работает, сопоставление с образцом в лямбда-выражении, похоже, работает вопреки интуиции. У меня есть встроенные комментарии.

struct X
{
  float operator () (float i) { return i*2; }
  // If the following is enabled, program fails to compile
  // mostly because of ambiguity reasons.
  //double operator () (float i, double d) { return d*f; } 
};

template <typename T>
struct function_traits // matches when T=X or T=lambda
// As expected, lambda creates a "unique, unnamed, non-union class type" 
// so it matches here
{
  // Here is what you are looking for. The type of the member operator()
  // of the lambda is taken and mapped again on function_traits.
  typedef typename function_traits<decltype(&T::operator())>::return_type return_type;
};

// matches for X::operator() but not of lambda::operator()
template <typename R, typename C, typename... A>
struct function_traits<R (C::*)(A...)> 
{
  typedef R return_type;
};

// I initially thought the above defined member function specialization of 
// the trait will match lambdas::operator() because a lambda is a functor.
// It does not, however. Instead, it matches the one below.
// I wonder why? implementation defined?
template <typename R, typename... A>
struct function_traits<R (*)(A...)> // matches for lambda::operator() 
{
  typedef R return_type;
};

template <typename F>
typename function_traits<F>::return_type
foo(F f)
{
  return f(10);
}

template <typename F>
typename function_traits<F>::return_type
bar(F f)
{
  return f(5.0f, 100, 0.34);
}

int f(int x) { return x + x;  }

int main(void)
{
  foo(f);
  foo(X());
  bar([](float f, int l, double d){ return f+l+d; });
}
18
ответ дан 28 November 2019 в 21:52
поделиться

Трюк void_t может помочь. Как работает `void_t` ?

Если у вас нет C ++ 17, вам нужно будет включить определение void_t:

template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;

Добавить дополнительный аргумент шаблона к исходному шаблону, по умолчанию равный void:

template <typename T, typename = void>
struct function_traits;

Объект признаков для простых функций такой же, как у вас уже есть:

template <typename R, typename... A>
struct function_traits<R (*)(A...)>
{
    using return_type = R;
    using class_type  = void;
    using args_type   = std:: tuple< A... >;
};

Для не методы const:

template <typename R, typename... A>
struct function_traits<R (*)(A...)>
{
    using return_type = R;
    using class_type  = void;
    using args_type   = std:: tuple< A... >;
};

Не забывайте const методы:

template <typename R, typename C, typename... A>
struct function_traits<R (C::*)(A...) const> // const
{
    using return_type = R;
    using class_type  = C;
    using args_type   = std:: tuple< A... >;
};

Наконец, важная черта. Для данного типа класса, включая лямбда-типы, мы хотим перейти от T к decltype(&T::operator()). Мы хотим убедиться, что эта черта доступна только для типов T, для которых ::operator() доступна, и это то, что void_t делает для нас. Чтобы применить это ограничение, нам нужно поместить &T::operator() в сигнатуру признака где-то, поэтому template <typename T> struct function_traits<T, void_t< decltype(&T::operator())

template <typename T>
struct   function_traits<T, void_t< decltype(&T::operator()) > > 
: public function_traits<           decltype(&T::operator())   >
{
};

Метод operator () в (не mutable, неуниверсальных) лямбдах const, что объясняет, почему нам нужен шаблон const выше.

1130 Но в конечном итоге это очень ограничительно. Это не будет работать с общими лямбдами или объектами с шаблонами operator(). Если вы пересмотрите свой дизайн, вы найдете другой, более гибкий подход.

2
ответ дан Community 28 November 2019 в 21:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: