7

私はクラスの状態に依存せず、それを変更しないでいくつかのoperator()オーバーロードを持つ多くの関数オブジェクトを持つライブラリを書いています。さて、私は自分のコードを多くの古いスタイルのAPIで動作させようとしました(これは無作為な必要性ではなく、実際にこのようなAPIを扱わなければなりませんでした)。過負荷。ある時点では、ポインタ演算子を機能させるにはあまりにも多くの変換が必要であり、理論的には単一の可変変換演算子を書くことができるはずです。ここでは、このような可変引数演算子を実装するクラスがある:あなたが見ることができるようにVariadic関数ポインタ変換

struct foobar 
{ 
    template<typename... Args> 
    using fptr_t = void(*)(Args... args); 

    template<typename... Args> 
    operator fptr_t<Args...>() const 
    { 
     return [](Args... args) { 
      // Whatever 
     }; 
    } 
}; 

が、私は私が持っているすべての関数オブジェクトはステートレスであるため、問題はない変換演算子を実装するためにポインタを機能させるラムダ変換を使用しました。期待の意味で、このコードをコンパイルする問題がない++

int main() 
{ 
    void(*foo)(int) = foobar(); 
    void(*bar)(float, double) = foobar(); 
} 

グラムを:目標は、次のようにクラスを使用できるようにしました。しかし、テンプレート置換障害エラーと打ち鳴らす++ rejects it

main.cpp:21:11: error: no viable conversion from 'foobar' to 'void (*)(int)' 
    void(*foo)(int) = foobar(); 
     ^   ~~~~~~~~ 
main.cpp:11:5: note: candidate function [with Args = int] 
    operator fptr_t<Args...>() const 
    ^
1 error generated. 

なお打ち鳴らすは++限り何の可変引数テンプレートが関与されていないような変換演算子には問題がありません。 1つのテンプレートパラメータを使用すると、コードのコンパイルに問題はありません。上記のコードは、コンパイラによって受け入れられるか拒否されるべきですか?

+4

私は(HTTPS [この一つとして同じバグ]この思う:// llvm.org/bugs/show_bug.cgi?id=24032)。リンクされたSOの質問もあります。リチャード・スミス[バグを言う](http://stackoverflow.com/questions/31225888/pre-typedefing-a-variadic-function-pointer-argument#comment50471304_31225888)私は彼を信じています:) –

+0

回避方法: 'template 演算子F *()'で変換し、関数型であることをsfinaeテストに追加し、特性を使用してargsを抽出し、ヘルパーを使用して解凍し、ヘルパーを使用してポインタに変換しますか? – Yakk

答えて

1

ラムダはキャプチャされない場合にのみ関数ポインタに変換できるため、コードは機能するはずです。だから私はCLANGのバグとしてそれを提出でしょう

The closure type for a non-generic lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function with C++ language linkage (7.5) having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.

:これは標準5.1.2/P6ラムダ式は[expr.prim.lambda]強調鉱山)で正当化されます。 CLANGための回避策として

以下に示すように、あなたはstd::functionに変換することができます:

struct foobar 
{ 
    template<typename... Args> 
    using fptr_t = void(*)(Args... args); 

    template<typename... Args> 
    operator std::function<void(Args...)>() const 
    { 
     return [](Args... args) { 
      //... 
     }; 
    } 
}; 

int main() 
{ 
    std::function<void(int)> f1 = foobar(); 
    std::function<void(double, float)> f2 = foobar(); 
    f1(1); 
    f2(2.0, 1.0f); 
} 

Live Demo

+0

ええ、私はそれをすべて知っています。私は自分の問題に対する解決策を求めているわけではない(私はもうしばらくそれを回してきた)。私はバグレポートを提出するコンパイラを知るために言語弁護士の回答を求めているだけです:p – Morwenn

+0

@MorwennあなたはCLANG:Pにバグレポートを提出します。 – 101010