2015-01-19 2 views
1

Я играю с методами фильтрации типов, переданных в перегруженные шаблоны функций. Я использую Visual Studio 2013.Вывод аргумента шаблона и SFINAE - с использованием std :: enable_if

Три части вопроса:

  1. Почему косяк мой компилятор выводить Blorg3?
  2. Является ли причина, что TFoo2(argc) генерирует ошибку компилятора так же, как и # 1?
  3. Есть ли способ передать параметры шаблона конструктору?

Вот пример кода:

#include <type_traits> 

#define IFPTR(T,R) typename std::enable_if<std::is_pointer<T>::value, R>::type 
#define IFINT(T,R) typename std::enable_if<std::is_integral<T>::value, R>::type 

template <class T, IFINT(T, T)* = nullptr> int Blorg1(T n) { return n + 1; } 
template <class T, IFPTR(T, T)* = nullptr> int Blorg1(T n) { return *n + 1; } 
template <class T> IFINT(T, int) Blorg2(T n)    { return n + 1; } 
template <class T> IFPTR(T, int) Blorg2(T n)    { return *n + 1; } 
template <class T> int Blorg3(IFINT(T, T) n)    { return n + 1; } 
template <class T> int Blorg3(IFPTR(T, T) n)    { return *n + 1; } 

struct TFoo1 { 
    template <class T, IFINT(T, T)* _ = nullptr> TFoo1(T n) { } 
}; 
struct TFoo2 { 
    template <class T> TFoo2(IFINT(T, T) n) { } 
}; 

int main(int argc, char* argv[]) 
{ 
    Blorg1(argc); // intellisense not happy 
    Blorg2(argc); 
    Blorg3<int>(argc); // why cant deduce? 
    Blorg1(*argv); // intellisense not happy 
    Blorg2(*argv); 
    Blorg3<char*>(*argv); // why cant deduce? 
    (void)TFoo1(argc); // intellisense not happy 
    (void)TFoo2(argc); // intellisense not happy and !!wont compile!! 
    return 0; 
} 
+2

1. Поскольку параметр шаблона появляется только в * inested-name-specifier *, который является не выводимым контекстом (т. Е. Этот параметр шаблона не выводится из аргументов в этот конкретный параметр). 2. yes 3. no – Columbo

ответ

1

Почему косяк мой компилятор выводить Blorg3?

В std::enable_if<std::is_pointer<T>::value, R>::type::type относится к вложенному имени, которое зависит от параметров шаблона T и R. Это не выводимый контекст (§14.8.2.5/5), поэтому компилятор не выводит аргумент шаблона.

Именно поэтому TFoo2 (argc) генерирует ошибку компилятора?

Да, шаблон конструктора должен иметь возможность выводить его аргументы шаблона, и в этом случае он не может.

Есть ли синтаксис для предоставления параметров шаблона конструктору?

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

+0

вывод параметров шаблона * есть * передача их ... –

+0

@MichaelGazonda Я не понимаю, что вы имеете в виду – Praetorian

+0

«Есть ли синтаксис для предоставления параметров шаблона конструктору?» - Да, вычет сделает это. Не было указано, требуется ли передача, чтобы она была явной или нет ... просто чтобы это нужно было сделать. –

2

Ответ на 1/2 о причине SFINAE не работает:

SFINAE и параметр шаблона вычет не хорошо играть вместе в этом контексте.

Или они делают так долго, как вы знаете о правильном порядке вещи происходят в.

вычет должен быть гарантированно работать, чтобы рассматриваться как возможная функция будет называться в этом случае.

Вот способ смотреть на это в менее техническом плане:

  1. Компилятор ищет возможные сигнатуры функций, которые соответствуют тому, что вы пытаетесь вызвать. [see overload resolution]

  2. Если он находит параметр шаблона, он смотрит, действительно ли он действителен для вычета.

И вот почему вы столкнулись с проблемами.Порядок, в котором происходят эти два события, - это то, почему SFINAE работает на Blorg1, Blorg2 и TFoo1, но не Blorg3 или TFoo2.

С Blorg3 и TFoo2 компилятор не может пропустить параметр, который вы передаете шаблону, поскольку он создает циклическую зависимость, которая не может быть разрешена.

template <class T> int Blorg3(IFINT(T, T) n)    { return n + 1; } 
template <class T> int Blorg3(IFPTR(T, T) n)    { return *n + 1; } 
Blorg3<char*>(*argv); // why cant deduce? 

Для решения SFINAE в Blorg3 здесь необходимо знать T. Тем не менее, T не известен, пока не разрешится SFINAE.

То же самое для почему TFoo2 не работает.

Часть 3 - о шаблонах и конструкторами

Да, вы можете передать параметры шаблона к конструкторам, но только если вы делаете это путем вычета таких, как то, что было сделано с TFoo1.

Вы не можете передать параметры шаблона конструктору.

+1

Спасибо, что объяснили это! Поскольку разрешение перегрузки игнорирует тип возврата, оба Blorg1 будут соответствовать проверке подписи. Параметр шаблона легко выводится как для blorg1, так и для 2 blorg1 генерируются с учетом типа. Одна из функций не позволяет выполнить последующую проверку синтаксиса. blorg2 работает одинаково. Когда достигается не выводимая версия blorg3, она не генерирует функцию. – johnnycrash