0

プログラムで可変個引数テンプレートを使用していましたが、予期しないエラーが発生しました。エラーを特定し、ショックを与えました。

#include<cctype> 
#include<iostream> // try to delete this line

class A 
{ 
    public: 
        void constructor() 
        {   } 

        template<typename... Args> 
        void constructor( int (*f)(int), Args... args ) 
        { 
            // process( f ) 
            constructor( args... ); 
        } 

        template<typename... Args> 
        A( Args... args ) 
        { 
            constructor( args... ); 
        } 
}; 

int main() 
{ 
    A a; 
    a.constructor( std::isspace ); // ok

    A b( std::isspace ); // error

    return 0; 
}

「#includeiostream」の行を削除すると、ソースは正常にコンパイルされます。ただし、この行を入力すると、コンパイラはエラーをスローします。

prov.cpp: In function ‘int main()’:
prov.cpp:32:22: error: no matching function for call to ‘A::A(<unresolved overloaded function type>)’
prov.cpp:32:22: note: candidates are:
prov.cpp:18:7: note: A::A(Args ...) [with Args = {}]
prov.cpp:18:7: note:   candidate expects 0 arguments, 1 provided
prov.cpp:4:7: note: constexpr A::A(const A&)
prov.cpp:4:7: note:   no known conversion for argument 1 from ‘&lt;unresolved overloaded function type>’ to ‘const A&’
prov.cpp:4:7: note: constexpr A::A(A&&)
prov.cpp:4:7: note:   no known conversion for argument 1 from ‘&lt;unresolved overloaded function type>’ to ‘A&&’

私はこのg++バージョンを使用しています:g ++(Ubuntu / Linaro 4.7.2-11precise2)4.7.2そして私はこのフラグでコンパイルしています:g++ -Wall -pedantic -std=c++11 prov.cpp -o prov

コンパイラがこのエラーをスローする理由がわかりません。バグの可能性はありますか?

4

2 に答える 2

3

これはコンパイラのバグではなく、可変個引数テンプレートの問題でさえ、std::isspace単にオーバーロードされています。.constructor直接呼び出す場合、最初の引数int (*f)(int)はコンパイラーに正しいオーバーロードを選択するのに十分な情報を提供しますが、ジェネリック引数はそうではありません。これは、例で簡単に示されます。

// our std::isspace
void foo(int){}
void foo(double){}

void test1(void (*f)(int)){}

template<class T>
void test2(T v){}

int main(){
  test1(foo); // compiles, compiler sees you want the 'int' overload
  test2(foo); // error, compiler has no clue which overload you want
              // and which type to deduce 'T' as
}

これは2つの方法で修正できます。

int (*f)(int) = std::isspace; // assign to variable, giving the compiler the information
A b(f); // already has concrete type here

// or
A b(static_cast<int(*)(int)>(std::isspace)); // basically the same as above, in one step
于 2013-03-15T14:12:37.823 に答える
2

問題は<cctype>、単一の関数を定義することですが、追加すると、からプルインされる別のオーバーロードisspaceが追加されます。からのものは<iostream>isspace<locale><cctype>

int isspace( int ch );

からのもの<locale>

template< class charT >
bool isspace( charT ch, const locale& loc );

両方を含めると、std::isspaceがあいまいになり、コードが失敗します。constructorこれは、コンパイラが何を転送するかを決定できないため、(ではなく)実際のctorを介してルーティングした場合にのみ表示されます。OTOH、メソッドconstructorは、両方のオーバーロードから選択する方法をコンパイラーにすでに指示しているパラメーターを取ります。

于 2013-03-15T14:19:43.597 に答える