2012-02-29 15 views
5

Estaba tratando de piratear un literal binario operator ""_b, pero me atasqué al tratar de terminar la recursión. ¿Cómo se define una función a la que se puede llamar usando una lista vacía de parámetros explícitos de la plantilla, que no entre en conflicto con una sobrecarga del paquete de parámetros? Luego, inspiración: unir la expansión del paquete vacío a algo loco.¿La expansión de un paquete de valores vacío coincide con un paquete de tipos o un parámetro de tipo opcional?

Pero GCC se queja de que los tipos inexistentes de la lista de argumentos vacíos no concuerdan con los tipos no requeridos explícitamente de la lista de parámetros. ¿Se supone que debe funcionar de esta manera?

template< char head, char ... tail > 
constexpr unsigned long long parse_binary() { 
    return ((head - '0') << sizeof ... (tail)) 
     + parse_binary< tail ... >(); // Error: no overload for termination. 
} 

template< typename = void > // I want this to match an empty pack of chars. 
// template< short = 0 > // even this would do. 
constexpr unsigned long long parse_binary() { 
    return 0; 
} 

template< char ... digits > 
constexpr unsigned long long operator ""_b() { 
    return parse_binary< digits ... >(); 
} 

#include <iostream> 

int main() { 
    std::cout << 010101_b << '\n'; 
} 

Nota: La pregunta no está implementando operator ""_b. Ese problema puede resolverse expandiendo el paquete a la lista de parámetros y pasando los tipos std::integral_constant.

Nota 2: Este código realmente funciona con un ajuste menor; ver mi respuesta a continuación. Pero eso no aborda directamente la pregunta. Hmm, tal vez debería haber editado esto en lugar de responder ...

+0

En general puede terminar la recursividad haciendo que la plantilla original 'plantilla ', y el uso 'template ' para la terminación, pero supongo que eso no es lo que estás pidiendo. –

+1

@ BjörnPollex No, luego pasar dos argumentos sería ambiguo. Los paquetes pueden estar vacíos. Una 'plantilla < char head >' y una 'plantilla harían el truco, pero sí, esa no es la pregunta. – Potatoswatter

Respuesta

0

No hay palabra oficial sobre el cumplimiento de tales complicado coincidencia, pero el código dado hace funciona si las dos sobrecargas se transponen.

La segunda sobrecarga de terminación no es visible para el primero porque la primera resuelve el nombre en el momento de definición de la plantilla. Solo las llamadas a funciones dependientes de un parámetro de plantilla tienen una búsqueda diferida hasta el momento de creación de instancias.

Para que quede claro, esto funciona :

template< typename = void > // Define this one first! 
constexpr unsigned long long parse_binary() { 
    return 0; 
} 

template< char head, char ... tail > 
constexpr unsigned long long parse_binary() { 
    return ((head - '0') << sizeof ... (tail)) 
     + parse_binary< tail ... >(); // Bingo: overload found. 
} 
+0

iirc en C++ 11 tenemos una viñeta explícita de que el nombre de una función depende si es una identificación de plantilla y uno de los argumentos de la plantilla es dependiente. ahora para saber que es una identificación de plantilla, el compilador primero tiene que buscarla en una plantilla, pero que no puedo evitar una segunda búsqueda de tiempo de creación de instancias. –

+0

sí Comprobé que se trata de un error de GCC: "parse_binary < tail ... >()" también debe hacer una búsqueda dependiente de instancia de "parse_binary". –

+0

@ JohannesSchaub-litb: ¡Interesante! ¿Has archivado el error? – Potatoswatter

4

¿No sería mejor terminar la recursión en un personaje?

template<char Ch> 
constexpr unsigned long long parse_binary(){ 
    return Ch - '0'; 
}; 

// second head to disambiguate 
template< char head1, char head2, char ... tail > 
constexpr unsigned long long parse_binary() { 
    return ((head1 - '0') << sizeof ... (tail)+1) + parse_binary< head2, tail ... >(); 
} 

En cualquier caso, el problema es que parse_binary de cero caracteres debe ser declarada antes de la versión variadic, como Clang señala muy bien:

error: call to function 'parse_binary' that is neither visible in 
     the template definition nor found by argument-dependent lookup 

// call trace... 

note: 'parse_binary' should be declared prior to the call site 
     constexpr unsigned long long parse_binary() { 
+0

LOL. Acabo de escribir mi respuesta a Björn antes de desplazarme a esto. Como dije en la nota, esta es una pregunta sobre paquetes de parámetros, no implementando literales binarios. La solución elegante es expandir el paquete en la lista de parámetros de función. – Potatoswatter

+0

Ah, sí, no está permitido expandir el conjunto de candidatos de sobrecarga a menos que el nombre sobrecargado dependa de ADL en un parámetro de plantilla. Aha, combinado con el comentario de Luc en el chat, creo que ahora lo entiendo. – Potatoswatter

Cuestiones relacionadas